我正在尝试建立一个测试,以检查某个文件是否定义了具有某个名称空间的标头保护。由于测试是通用的,因此仅在编译时才知道此名称空间,并以形式传入-DTHENAMESPACE=BLA。然后,我们使用/sf/answers/104298981/的一些魔术将它们粘贴在一起。
这意味着我想做类似的事情:
#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
Run Code Online (Sandbox Code Playgroud)
但这不能正常工作,因为cpp抱怨ifndef括号不正确。
如果有可能,我该如何正确地做到这一点?
我也尝试过添加更多的间接层,但是没有取得很大的成功。
因此,直接执行#ifdef此操作至少似乎是不可能的:
考虑到defined运营商:
如果定义的运算符是由于宏扩展而出现的,则C标准表示该行为是undefined。GNU cpp将其视为真正的定义运算符,并对其进行正常评估。如果您使用命令行选项-Wpedantic,它将在您的代码使用此功能的任何地方发出警告,因为其他编译器可能会以不同方式处理它。该警告也可以通过-Wextra启用,也可以通过-Wexpansion-to-defined单独启用。
https://gcc.gnu.org/onlinedocs/cpp/Defined.html#Defined
并ifdef预期会出现MACRO,并且不会进一步扩展。
https://gcc.gnu.org/onlinedocs/cpp/Ifdef.html#Ifdef
但是也许有可能触发“未定义的常量”警告(-Wundef),这也将使我的测试管道能够解决此问题。
如果我们假设包括后卫总是看起来像
#define NAME /* no more tokens here */
Run Code Online (Sandbox Code Playgroud)
并且,如您所说,如果可以接受任何编译时错误(而不是#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)
Run Code Online (Sandbox Code Playgroud)
在这里,NAMESPACE(API_H)尝试连接BLA_API_H并+使用##。
这导致error: pasting "BLA_API_H" and "+" does not give a valid preprocessing token 除如果BLA_API_H被#define剐到“无令牌”。
存在时#define BLA_API_H,NAMESPACE(API_H)简单地变成
static int UNUSED_/*line number here*/ = +1;
Run Code Online (Sandbox Code Playgroud)
如果您选择了一个不太健壮的解决方案,甚至可以得到不错的错误消息:
#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
Run Code Online (Sandbox Code Playgroud)
在此,如果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意外地将其定义为真实的东西,那么您会得到错误的ne俩。