使用_Generic实现“安全”数学运算的合理方法?

时间:2014-08-08 21:38:56

标签: c generics integer-arithmetic

我一直在考虑一种方法,可以更安全地使用C&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");
}

以上输出类似于:

Integer wrap-around occurred, File: /.../main.c, Line: 41

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

显然,需要添加额外的操作和类型以及处理签名算术,但是我可能会遗漏这个整体方法有什么问题吗?

是否有一种更简单的方式来写这个我忽略的东西?

1 个答案:

答案 0 :(得分:0)

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

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

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

[1]例如 fgetc