我试图构建一个测试,检查某个文件是否定义了具有特定名称空间的头保护。因为测试是泛型的,所以只有在编译时才知道这个名称空间,并作为-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#defined到“无标记”。
当出现#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_HXTRUTHY_VALUE_BLA_API_HX由于未定义而计算为false
这里的问题是,如果TRUTHY_VALUE_BLA_API_HX意外地被定义为一些真实的东西,您将得到一个假否定。

关于c - 检查构造的常量是否为#define,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55243068/

10-11 23:03