我的部分代码取决于预处理器符号的值:
int a()
{
#if SDK_VERSION >= 3
return 1;
#else
return 2;
#endif
}
比较取决于SDK_VERSION的值。它应该是一个整数或比较整数的东西,在本例中为3.如果SDK_VERSION是无法与整数比较的东西,则会出现编译错误。
如果SDK_VERSION不是预期的类型,有没有办法中止编译?例如:
#if type(SDK_VERSION) != int # Does not compile, I know
#error "SDK_VERSION must be an integer."
#endif
答案 0 :(得分:12)
使用模板生成此类错误:
template<typename T> struct macro_error;
template<> struct macro_error<int> {};
template<typename T> void check(T)
{
macro_error<T> SDK_VERSION_must_be_int;
}
int ignored = (check(SDK_VERSION), 0);
如果SDK_VERSION
不是int,则此代码将生成编译错误,其中包含以下字符串:
SDK_VERSION_must_be_int
请参阅以下演示:
#define SDK_VERSION 1.0
)#define SDK_VERSION 1
)并且还注意到第一种情况中的错误消息。它打印出来:
prog.cpp:9: error: ‘SDK_VERSION_must_be_int’ has incomplete type
prog.cpp:9: warning: unused variable ‘SDK_VERSION_must_be_int’
答案 1 :(得分:4)
不。原因是预处理器符号根本没有类型。
预处理器符号最好被认为只是一个字符串。 C的类型系统直到编译步骤才真正存在,这在预处理器运行之后就会发生。
答案 2 :(得分:2)
如果SDK_VERSION
是一个字符串,这将无法编译(但它适用于float
...):
int get_SDK_Version()
{
return SDK_VERSION;
}
答案 3 :(得分:0)
预处理程序不了解类型或任何语言关键字。
答案 4 :(得分:0)
我想你可以在这里拉一些模板元编程。
如果我有所作为,我会尝试自己的魔法并发布一个例子。我的理论是你可以实例化一个类或函数模板。如果模板的默认定义不合适,则会导致编译错误。但int
的模板专门化不会导致错误。
这超出了我对模板和预处理器魔术的经验范围,但值得一看。我期待的一个问题是SDK_VERSION
实际上并不仅仅是要替换的符号。 SDK_VERSION
本身没有类型。
充其量,我认为你可以检查它可以转换成什么类型,但是预处理器定义为“常量”的概念非常......暴力,几乎是hackish。这可能是一种常见的做法,但它根本不安全。最好记住它们只是查找和替换的预处理器版本。
答案 5 :(得分:0)
事实上,#if指令将整数的权利视为整数。
因此,如果你想达到你所要求的,你必须做一些算术。例如,使用以下命令执行test.c文件:
#define VERSION 7
#if VERSION
#if VERSION - (VERSION % 10 )
#warning Number out of range (1-9)
#else
#warning Number in range (1-9)
#endif
#else
#warning Zero or not a number
#endif
使用
进行编译gcc -c -o /dev/null test.c
您将收到消息: “零不是数字”...如果您的VERSION为0,或者不作为整数评估(预处理器)。
如果VERSION按整数评估,您将根据其值获得第一条或第二条消息。
这将允许您执行您要搜索的内容。
#if:http://gcc.gnu.org/onlinedocs/cpp/If.html
上的文档请注意,整数可以表示为:123或0xCC,或者在递归宏扩展后计算为整数常量的任何内容。
如果数字是浮点数,如:3.14则认为是零。
你不能简单地将0(整数)与不是整数的东西区分开来。但是,使用宏字符串连接可能存在一种可能性,但仍有待探索。
答案 6 :(得分:0)
好主意@Navaz! 我必须找到特定类型的参数进行简单的调整,并且很容易找到未列出类型的剩余调用,以防万一:
template<typename T> struct ints_error;
template<typename T> struct double_error;
template<> struct ints_error<uint8_t> {};
template<> struct ints_error<uint16_t> {};
template<> struct ints_error<int64_t> {};
template<> struct double_error<double> {};
template<typename T> int check_int(T)
{
ints_error<T> must_be_listed;
(void)must_be_listed;
return 0;
}
template<typename T> int check_double(T)
{
double_error<T> must_be_double;
return must_be_double, 0;
}
#define sqlite3_bind_int(a,b,c) check_int(c);
#define sqlite3_bind_int64(a,b,c) check_int(c);
#define sqlite3_bind_double(a,b,c) check_double(c);