我试图构建一个测试,检查某个文件是否定义了具有特定名称空间的头保护。因为测试是泛型的,所以只有在编译时才知道这个名称空间,并作为-DTHENAMESPACE=BLA
传入然后我们使用https://stackoverflow.com/a/1489985/1711232中的一些魔法将其粘贴在一起。
这意味着我想做如下事情:
#define PASTER(x, y) x##_##y
#define EVALUATOR(x, y) PASTER(x, y)
#define NAMESPACE(fun) EVALUATOR(THENAMESPACE, fun)
#ifndef NAMESPACE(API_H) // evaluates to BLA_API_H
# error "namespace not properly defined"
#endif
但这并不能正常工作,cpp抱怨
ifndef
不需要括号。如果可能的话,我该怎么做呢?
我也试过添加更多的间接层,但没有很多成功。
因此,直接、正确地执行
#ifdef
至少看起来是不可能的:考虑到
defined
运算符:如果定义的运算符是宏扩展的结果,那么C标准会说该行为是未定义的GNU cpp将其视为真正定义的运算符,并对其进行正常评估如果您使用命令行选项Wpedantic,则无论您的代码在何处使用此功能,它都会发出警告,因为其他编译器可能会以不同的方式处理它警告也由-Wextra启用,也可以通过-Wexpansion to defined单独启用。
https://gcc.gnu.org/onlinedocs/cpp/Defined.html#Defined
ifdef
需要一个宏,并且不做进一步的扩展。https://gcc.gnu.org/onlinedocs/cpp/Ifdef.html#Ifdef
但可能会触发“未定义常量”警告(
-Wundef
),这也会允许我的测试管道捕获此问题。 最佳答案
如果我们假设包括警卫
#define NAME /* no more tokens here */
如果如您所说,任何编译时错误(而不是
#error
独占)都是可以接受的,那么您可以执行以下操作:#define THENAMESPACE BLA
#define BLA_API_H // Comment out to get a error.
#define CAT(x,y) CAT_(x,y)
#define CAT_(x,y) x##y
#define NAMESPACE(x) static int CAT(UNUSED_,__LINE__) = CAT(CAT(THENAMESPACE,CAT(_,x)),+1);
NAMESPACE(API_H)
在这里,
NAMESPACE(API_H)
尝试使用BLA_API_H
连接+
和##
。这将导致
error: pasting "BLA_API_H" and "+" does not give a valid preprocessing token
除非BLA_API_H
是#define
d到“无标记”。当出现
#define BLA_API_H
时,NAMESPACE(API_H)
就变成static int UNUSED_/*line number here*/ = +1;
如果您满足于不太可靠的解决方案,您甚至可以得到很好的错误消息:
#define THENAMESPACE BLA
#define BLA_API_H // Comment out to get a error.
#define TRUTHY_VALUE_X 1
#define CAT(x,y) CAT_(x,y)
#define CAT_(x,y) x##y
#define NAMESPACE(x) CAT(CAT(TRUTHY_VALUE_,CAT(THENAMESPACE,CAT(_,x))),X)
#if !NAMESPACE(API_H)
#error "namespace not properly defined"
#endif
在这里,如果定义了
BLA_API_H
,则#if !NAMESPACE(API_H)
扩展为#if 1
。如果未定义
BLA_API_H
,则它将扩展为#if TRUTHY_VALUE_BLA_API_HX
,TRUTHY_VALUE_BLA_API_HX
由于未定义而计算为false
。这里的问题是,如果
TRUTHY_VALUE_BLA_API_HX
意外地被定义为一些真实的东西,您将得到一个假否定。关于c - 检查构造的常量是否为#define,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55243068/