如何检查参数是否是 C 预处理器宏中的整数常量表达式? [英] How to check if a parameter is an integral constant expression in a C preprocessor macro?

查看:12
本文介绍了如何检查参数是否是 C 预处理器宏中的整数常量表达式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm currently cleaning up an existing C-library to publish it shamelessly.

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

A preprocessor macro NPOT is used to calculate the next greater power of two for a given integral constant expression at compile time. The macro is normally used in direct initialisations. For all other cases (e.g. using variable parameters), there is an inline function with the same function.

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

But if the user passes a variable, the algorithm expands to a huge piece of machine code. My question is: What may I do to prevent a user from passing anything but an integral constant expression to my macro?

#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
}

我已经尝试过的:

  1. 将宏定义为#define NPOT(x) complex_algorithm(x ## u).它仍然可以工作并且抛出一个 - 即使几乎没有帮助 - 变量参数的编译器错误.除非没有像 iu 这样的变量……脏的、危险的,不要它.
  2. 文档,不适用于大多数用户.
  1. Define the macro to #define NPOT(x) complex_algorithm(x ## u). It still works and throws a - even if hardly helpful - compiler error for variable parameters. Unless there is no variable like iu... Dirty, dangerous, don't want it.
  2. Documentation, didn't work for most users.

推荐答案

您可以使用任何需要常量整数表达式的表达式,然后将其优化出来.

You can use any expression that needs a constant integral expression and that will then be optimized out.

#define NPOT(X)                                         
 (1                                                     
 ? complex_algorithm(X)                                 
 : sizeof(struct { int needs_constant[1 ? 1 : (X)]; })  
 )

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

eventually you should cast the result of the sizeof to the appropriate integer type, so the return expression is of a type that you'd expect.

我在这里使用一个未标记的 struct

I am using an untagged struct here to

  • 有一个类型,所以真的不会产生临时的
  • 具有唯一的类型,这样表达式可以在代码中的任何位置重复而不会引起冲突
  • 触发使用 VLA,从 C99 开始,struct 内不允许使用 VLA:
  • have a type so really no temporary is produced
  • have a unique type such that the expression can be repeated anywhere in the code without causing conflicts
  • trigger the use of a VLA, which is not allowed inside a struct as of C99:

结构或联合的成员可以有任何对象类型,而不是可变修饰类型.

A member of a structure or union may have any object type other than a variably modified type.

我使用三元 ?:1 作为选择表达式,以确保始终根据其类型评估 :,但是从不作为表达式求值.

I am using the ternary ?: with 1 as the selecting expression to ensure that the : is always evaluated for its type, but never evaluated as an expression.

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

It seems that gcc accepts VLA inside struct as an extension and doesn't even warn about it, even when I explicitly say -std=c99. This is really a bad idea of them.

对于这样一个奇怪的编译器 :) 你可以改用 sizeof((int[X]){ 0 }).这和上面的版本一样被禁止",但另外甚至 gcc 也抱怨它.

For such a weird compiler :) you could use sizeof((int[X]){ 0 }), instead. This is "as forbidden" as the above version, but additionally even gcc complains about it.

这篇关于如何检查参数是否是 C 预处理器宏中的整数常量表达式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆