c - 使用 _Generic 实现 "safe"数学运算的合理方法?

标签 c generics integer-arithmetic

我一直在考虑一种方法,使它更容易安全地使用 C 的基本数据类型进行数学运算(例如使用 CERT C coding standard )。到目前为止,我想出了这样的事情:

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>

#define safe_add(x, y) _Generic((x + y),                    \
                            unsigned int: safe_add_uint,    \
                           unsigned long: safe_add_ulong    \
                       )(x, y, __FILE__, __LINE__)

unsigned long
safe_add_ulong(unsigned long x, unsigned long y,
               const char* filename, int line_num)
{
    if (x < ULONG_MAX - y)
        return x + y;
    else {
        fprintf(stderr,
                "Integer wrap-around occurred, File: %s, Line: %d\n",
                filename, line_num);
        exit(EXIT_FAILURE);
    }
}

unsigned int
safe_add_uint(unsigned int x, unsigned int y,
              const char* filename, int line_num)
{
    if (x < UINT_MAX - y)
        return x + y;
    else {
        fprintf(stderr,
                "Integer wrap-around occurred, File: %s, Line: %d\n",
                filename, line_num);
        exit(EXIT_FAILURE);
    }
}

int
main()
{        
    /*  
     *  usual arithmetic conversions results in this calling
     *  the uint version of safe_add...
     */
    safe_add(2000000000, 3000000000u));

    printf("We shouldn't get here...(unless unsigned int uses more than 32 bits)\n");
}

上面的输出类似于:

发生整数环绕,文件:/.../main.c,行:41

并且程序以失败代码退出(假设操作系统支持)。

显然,需要添加额外的操作和类型以及处理带符号的算术,但是这个整体方法是否有任何我可能遗漏的问题?

有没有更简单的方法来写这个我忽略了?

最佳答案

这段代码可能是库式的,只是它fprintfsstderr。相反,您可以想出一种方法将错误直接传达给调用者,然后调用者可以选择优雅地处理它。您可以拆分这些代码,使错误报告和退出代码与执行计算并注意到错误的“安静”代码分开。

例如,您会注意到几个 C 函数 [1] 返回一个 int 值,即使它们处理的是字节。这使他们有“空间”来传达特殊的 EOF 条件以及所有字节值。

如果您无法在返回值中传达您的错误条件,您可以使用指针参数将状态传达回调用者。

[1]如fgetc

关于c - 使用 _Generic 实现 "safe"数学运算的合理方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25212634/

相关文章:

c - 如何读取libxml2中的小数?

c - SetSystemCursor 不为 *.ani 光标设置动画

java - 'int' 类型的大数组需要传递给通用数组和集合

c - 将两个无符号 32 位整数相减并赋值给 64 位有符号整数

c++ - 在 C/C++ 中乘以小数(相对于高数)是否更快?

c - Mkdir() permission denied C/linux 编程

java - 为什么 Maven 不编译 Guava Table 代码而 Eclipse 编译器编译? (推断类型不符合上限)

c# - C# 中的 Foreach struct 奇怪的编译错误

c# - 在 C# 整数运算中,a/b/c 是否总是等于 a/(b*c)?

c - 是否有更惯用的方法来防止释放可选参数字符串?