C99或GCC/Clang中的值参数是否可以进行编译时检查?

C99或GCC/Clang中的值参数是否可以进行编译时检查?,gcc,clang,c99,Gcc,Clang,C99,我有一个函数,它的长度值必须不大于32768。我想在编译时检查这种情况,因为在嵌入式系统中没有处理这种故障的好方法。此外,传入的长度值应始终是编译时常量,通常为sizeof() 这在C99或GCC/Clang扩展中可能吗 类似这样的东西,显然不会编译,因为len不是整型常量 #include <assert.h> void fucntion(const uint16_t len) { _Static_assert(len <= 32768, "length parame

我有一个函数,它的长度值必须不大于32768。我想在编译时检查这种情况,因为在嵌入式系统中没有处理这种故障的好方法。此外,传入的长度值应始终是编译时常量,通常为
sizeof()

这在C99或GCC/Clang扩展中可能吗

类似这样的东西,显然不会编译,因为
len
不是整型常量

#include <assert.h>
void fucntion(const uint16_t len)
{
    _Static_assert(len <= 32768, "length parameter too large");
}

正如Nate Eldredge指出的,有一个GCC(和Clang)允许您返回参数。

您可以使用旧技巧编写静态断言,使用
sizeof
和负数组,并在调用端进行宏扩展:

void function_real(const uint16_t len);

#define function(len) ((void)sizeof(char[len > 32768 ? -1 : 1]), function_real(len))
在将C与可变长度数组一起使用的情况下,数组的
sizeof
将与非整数常量表达式的表达式一起使用。对于静态断言,可以使用旧的位字段技巧将
len
强制为整数常量表达式。如此相似,但更好:

 #define function(len) ((void)sizeof(struct{ int a:len > 32768 ? -1 : 1;}), function_real(len))
您可以像使用
…\u FORTIFY\u SOURCE
一样,使用gnu内置的编译优化和启用的优化:

void function_real(const uint16_t len);

static inline 
void function(const uint16_t len) {
     if (!__builtin_constant_p(len)) {
            extern __attribute__(( __error__ ( "Och no! len couldn't be evaulated at runtime" ) ))
            void compile_time_error(void);
            compile_time_error();
     } else if (len > 32768) {
            extern __attribute__(( __error__ ( "Och no! len is too small!" ) ))
            void compile_time_error2(void);
            compile_time_error2();
     }

     function_real(len);
}

注意到一些小问题,一种可能性是:

#define func(len, buffer)                                           \
({                                                                  \
    _Static_assert(len < 32768, "Length exceeds size of EEPROM");   \
    _func(len, buffer);                                             \
})


bool _func(uint16_t len, const void *buffer)
{ }
#定义函数(len,buffer)\
({                                                                  \
_静态断言(len<32768,“长度超过EEPROM的大小”)\
_func(len,buffer)\
})
布尔函数(uint16长度,常量无效*缓冲区)
{ }
感谢内特·埃尔德雷奇


这种技术的缺点是IDE在浏览代码时只显示有关宏的信息,因此,例如,您不会得到有关参数类型的提示。不过,在编译时,您仍然会得到通常的检查和错误。

使用宏并在调用端检查长度<代码>整型常量->它是“整型”的,就像“整型常量表达式”一样。@KamilCuk我刚刚添加了一个关于宏选项的注释。它是“积分常数”,这是一个术语,用于表示编译器在编译时可以计算的东西,它们是_Static_assert宏所必需的。它不必是整数,它可以是任何类型。我不太明白反对宏的理由。如果宏扩展包含对实函数的调用,则可以获得所有相同的好处。例如,
#定义func(l,b){u Static\u断言(l@NateEldredge它可以工作,但大多数IDE将无法进行适当的提示或预编译检查。这不是世界末日,但如果有更好的选择就好了。遗憾的是,我认为没有。@user11567957:您可以使用gcc和clang都支持的扩展来解决这个问题。
\define func(l,b)({{u Static}断言(l)
#define func(len, buffer)                                           \
({                                                                  \
    _Static_assert(len < 32768, "Length exceeds size of EEPROM");   \
    _func(len, buffer);                                             \
})


bool _func(uint16_t len, const void *buffer)
{ }