如何检查参数是否为C预处理程序宏中的整数常量表达式? [英] How to check if a parameter is an integral constant expression in a C preprocessor macro?
问题描述
我目前正在清理现有的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
}
我已经尝试过的:
- 将宏定义为
#define NPOT(x) complex_algorithm(x ## u)
.它仍然可以工作,并且会为变量参数抛出(即使几乎没有帮助)编译器错误.除非没有iu这样的变量,否则...肮脏,危险,不要. - 文档,不适用于大多数用户.
- 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. - 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屋!