检查宏参数是否为文字

时间:2018-03-12 14:10:04

标签: c c-preprocessor opencl

有没有办法在编译时检查宏的参数是否是整数文字,并在这种情况下以不同的方式评估宏?

#include <stdio.h>

#define VALUE_0 0
#define VALUE_1 2
#define VALUE_2 4
#define VALUE_3 6
#define VALUE_4 8

#define VALUE(_idx_) VALUE_ ## _idx_

#define VALUE_(_idx_) 2*(_idx_)

int main() {
    printf("%i\n", VALUE(3));
    printf("%i\n", VALUE_(1+2));
}

VALUE(3)始终在编译时解析,但仅在3为整数文字时才有效。 VALUE_(3)适用于任何参数类型,但可能会导致在运行时计算的表达式(在更复杂的情况下),并且无法进行编译器优化。

如果有办法编写宏,则会自动解析为VALUE_VALUE,具体取决于参数是否为整数文字。

编辑:

它适用于C程序,或者更具体地说是OpenCL C.似乎对于某些OpenCL C编译器(例如NVidia nvcc和Intel),类似VALUE(idx)的表达式并不总是在编译时解析,即使论证是一个常数。 (或者,如果内核包含这样的表达式,则至少内核不会自动向量化。)例如,如果VALUE()解析为包含switch语句的内联函数的调用,或者查找一个constant数组,它不起作用,但如果它是一个嵌套的?:表达式,它可以工作。 VALUE_将保证解析为常量。

因为我在运行时从主机生成C源代码并将其传递给OpenCL C编译器,所以不必为每个数组生成两个不同的宏是有用的。

2 个答案:

答案 0 :(得分:1)

我建议始终使用后者:

#define VALUE_(_idx_) 2*(_idx_)

如果参数是常量或常量表达式,则编译器将评估预处理器之后的结果表达式。如果不是,它将在运行时进行评估。

在整数文字的情况下,两个宏之间的唯一区别是预处理器是否为您提供最终结果或编译器是否提供了结果。在这两种情况下,都没有运行时开销,因此最好使用能够提供最大灵活性的开销。

答案 1 :(得分:0)

我会把问题放在首位,并建议您尝试强制编译器计算该值(另外好处是断言该值实际上是编译时常量):

#define MAKE_ME_CONSTANT(x) sizeof((struct{char c[x];}){{0}}.c)

这(从an earlier answer of mine调整)声明了一个匿名结构,其中char - 数组成员的大小是你的常量。然后使用复合文字对其进行实例化,并检索成员的大小。所有这些都是sizeof的未评估操作数的一部分,所以我希望任何编译器都能使它成为常量。

注意:我没有使用更简单的sizeof(char[x]),因为那可能是VLA。但是VLA不能是结构成员,所以我们在这里很好。

因此,你得到:

#define VALUE(_idx_) MAKE_ME_CONSTANT(2*(_idx_))