如何检查参数是否是 C 预处理器宏中的整型常量表达式?
我目前正在清理现有的 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
}
我已经尝试过的方法:
- 将宏定义为
#define NPOT(x) complex_algorithm(x ## u)
。它仍然有效,并会抛出一个变量参数的编译器错误(即使几乎没有帮助)。除非没有iu这样的变量……肮脏,危险,不要。 - 文档对大多数用户不起作用。
I'm currently cleaning up an existing C-library to publish it shamelessly.
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
}
What I already tried:
- 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您可以使用任何需要常量积分表达式的表达式,然后将其优化掉。
最终您应该将
sizeof
的结果转换为适当的整数类型,以便返回表达式是您期望的类型。我在这里使用未标记的 struct 来
struct
中使用:我使用三元
?:
和1
作为选择表达式,以确保:
始终评估其类型,但从未评估为一个表达。编辑:看起来gcc接受
struct
内部的VLA作为扩展,甚至没有警告它,即使我明确地说-std=c99.他们这实在是一个坏主意。
对于这样一个奇怪的编译器:)你可以使用
sizeof((int[X]){ 0 })
来代替。这与上面的版本一样“被禁止”,而且甚至 gcc 也抱怨它。You can use any expression that needs a constant integral expression and that will then be optimized out.
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.I am using an untagged
struct
here tostruct
as of C99:I am using the ternary
?:
with1
as the selecting expression to ensure that the:
is always evaluated for its type, but never evaluated as an expression.Edit: 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.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.如果 x 不是整型常量表达式,则会出现编译错误。
请注意,此解决方案不适用于初始化静态变量:
将触发编译错误,因为带有
,
的表达式不是常量表达式。正如 @JensGustedt 在注释中所说,解析为负整数的整数常量表达式不能在此解决方案中使用,因为位字段宽度不能为负。
This will give a compile error if
x
is not a integral constant expression.Note that this solution does not work for initializing a static variable:
will trigger a compile error because of an expression with
,
is not a constant expression.As @JensGustedt put in the comment, an integral constant expression resolving to a negative integer number cannot be used in this solution as bit-field width cannot be negative.