如何检查参数是否是C预处理器宏中的整数常量表达式?

Lut*_*utz 6 c macros constant-expression c-preprocessor

我目前正在清理现有的C库,以无耻地发布它.

预处理器宏NPOT用于在编译时计算给定积分常量表达式的下一个更大的2的幂.宏通常用于直接初始化.对于所有其他情况(例如,使用变量参数),存在具有相同功能的内联函数.

但是,如果用户传递变量,则算法会扩展为大量的机器代码.我的问题是: 我可以做些什么来防止用户向我的宏传递除了一个整数常量表达式之外的任何内容?

#define NPOT(x)   complex_algorithm(x)

const int c=10;
int main(void) {
    int i=5;

    foo = NPOT(5);   // works, and does everything it should
    foo = NPOT(c);   // works also, but blows up the code extremely
    foo = NPOT(i);   // blows up the code also
}
Run Code Online (Sandbox Code Playgroud)

我已经尝试过的:

  1. 将宏定义为#define NPOT(x) complex_algorithm(x ## u).它仍然可以工作并抛出 - 即使几乎没有帮助 - 变量参数的编译器错误.除非没有像iu这样的变量......脏,危险,不要它.
  2. 文档,对大多数用户不起作用.

Jen*_*edt 6

您可以使用任何需要常量积分表达式的表达式,然后进行优化.

#define NPOT(X)                                         \
 (1                                                     \
 ? complex_algorithm(X)                                 \
 : sizeof(struct { int needs_constant[1 ? 1 : (X)]; })  \
 )
Run Code Online (Sandbox Code Playgroud)

最终你应该将结果sizeof转换为适当的整数类型,因此返回表达式是你期望的类型.

我在struct这里使用没有标记的

  • 有一个类型所以真的没有临时产生
  • 具有唯一类型,使得表达式可以在代码中的任何位置重复,而不会引起冲突
  • 触发使用VLA,这在structC99中是不允许的:

结构或联合的成员可以具有除可变修改类型之外的任何对象类型.

我使用的三元?:1作为选择的表达,以确保:始终是评价其类型,但绝不会当做表达式.

编辑:似乎gcc接受VLA内部struct作为扩展,甚至没有警告它,即使我明确说-std=c99.这对他们来说真是个坏主意.

对于这样一个奇怪的编译器:)你可以使用sizeof((int[X]){ 0 }),而不是.这与以上版本一样"被禁止",但即使是gcc也会抱怨它.