编译时的硬限制参数值

时间:2015-03-24 11:39:05

标签: c c-preprocessor buffer-overflow

假设我们有一个数组:

struct some array[] = {A, B, C, D};

并且假设我们有一个函数,在给定索引参数的情况下,使用该值执行某些操作:

void sfrugula(size_t index){
    do_it( &array[index] );
}

现在,我们知道我们几乎总是用STATIC值而不是变量来调用该函数,例如:

sfugula(10);

有没有办法检查编译时是否有溢出,是否有抛出错误?

重点是硬限制并在编译时检查参数(如果可能),因为这不仅可以应用于数组,甚至可以应用于某些变量。

5 个答案:

答案 0 :(得分:1)

这是我的解决方案,它使用枚举和X宏:

我创建了一个外部文件" ports.h"。 X()的左边元素是用户"使用的"漂亮的名称,右边是相应的REAL值(或者它的唯一部分,如下所示)

#ifdef DDRA && PORTA && PINA
X(A, AAA)
#endif
#ifdef DDRB && PORTB && PINB
X(B, BBB)
#endif

然后进入另一个文件我声明了枚举(A,B,....)和指向真实元素的指针的并行数组(在这种情况下,女巫是my_AAA,my_BBB等......)

#define SEP ,
#define X(a, b) a SEP
enum PORTS {
    #include "ports.h"
};
#undef X

/* here we initialize the array of structure */
#define X(a, b) &my_##b SEP
static const uint8_t *array[] =
{
    #include "ports.h"
};
#undef X
#undef SEP

最后只需更改我们的函数即可使用枚举

void sfrugula(enum PORTS p){
    do_it( &array[p] );
}
我必须要做的唯一不同的事情是在使用函数时使用枚举而不是数值,但是如果我忘了,编译器不会发出警告;现在我正在寻找一些typedef magic来实现这一目标(在C ++中,如果使用&#34,它已经很好了; -Wenum-compare"默认情况下,如果使用" -Wall& #34)

答案 1 :(得分:0)

使用枚举(枚举)。这样,您可以将变量的值限制为某个整数集。 请注意,枚举仅作为整数使用,并且适用于相对较小的值。

答案 2 :(得分:0)

即使定义和用法是并排的,编译器也不会检查数组索引。

int array[3];
array[10] = 0;

这是一个设计它的解决方案,但是很笨拙:

#include<stdio.h>

#define ARRMAX  3
#define INDEX   10

int main()
{
    int array[ARRMAX];
    #if INDEX >= ARRMAX
    #error Array index is out of range
    #endif
    array[INDEX] = 0;
    return 0;
}

编译器输出:

test.c(10) : fatal error C1189: #error :  Array index is out of range

但是你不能在函数中执行它,你必须在调用函数时执行它,知道函数的功能。在运行时更好地解决这个问题,在函数中,你可以检查传递的静态值和变量值。

答案 3 :(得分:0)

sfrugula函数内部,不,没有办法进行编译时检查。

C使用非常简单的构建系统,编译器不关心这些事情。它实际上只是通过你的代码根据参数列表和它们内部的语句为每个函数吐出汇编程序。当然它可以进行这些类型的检查,但请记住,超出范围的数组访问仍然是兼容的C代码,除了强制执行之外,大多数C编译器都不会判断您如何使用或滥用该语言。

另一方面,预处理器提供了一些编译时验证的能力,但这并没有扩展到你想要做的事情。因此,最佳选择是检查每个位置sfugula的范围,或添加仅在调试模式下使用的运行时检查。但是,除非您的系统受到严重的资源限制,否则通常只需在生产代码中包含错误检查并使用适当的故障机制即可。了解程序如何处理这样的错误,即使您认为可以通过静态检查来缓解这种错误,也会使您的程序更加健壮。

答案 4 :(得分:0)

这并没有直接回答这个问题,因为它没有提供在编译时进行检查的机制。但是,在没有(显而易见的)方法的情况下,我建议,除非您正在构建将由第三方开发人员调用的库API,否则您应该提供一种执行运行时范围检查的机制。在完成详尽的测试后,可以禁用发布版本。

(对于公共API,离开范围检查非常重要。)

您可以在宏中对函数进行包装调用,可以为发布版本禁用该函数。

#ifdef DEBUG
    #define SAFE_sfrugula(index) do\
    {\
        if(index < ((sizeof array) / (sizeof array[0]))) \
            sfrugula(index);\
        else\
        {
            printf("sfrugula index out of range on line %d",__LINE__);\
            exit(-1);\
        }\
    } while(0)
#else
    #define SAFE_sfrugula(index) sfrugula(index)
#endif