c - 检查构造的常量是否为#define'd
问题描述
我正在尝试构建一个测试来检查某个文件是否定义了具有某个命名空间的标头保护。因为测试是通用的,所以这个命名空间只在编译时是已知的,并以-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
this 至少似乎是不可能的:
考虑defined
运营商:
如果定义的运算符作为宏扩展的结果出现,则 C 标准说行为是未定义的。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 */
如果,如您所说,任何编译时错误(而不是#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
except if BLA_API_H
is #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
意外地被定义为真实的东西,你会得到一个错误的否定。
推荐阅读
- javascript - 反应:未捕获的类型错误:X 不是函数
- spring-cloud-stream - 消息的手动确认(检查点):Spring Cloud Stream Kenesis Binder
- java - 为什么我的 Java 代码抛出 NoSuchElementException: No line found
- python - 如何检查我的数据框中的特定股票代码字符串,列名称为 Name 并在数据框中找到它时返回?
- android - 如何在没有实际启动活动的情况下检查外部应用程序的活动是否已“导出 = false”
- bash - Bash:“nl”:摆脱每个行号之前的多余空格的最佳方法是什么?
- spring - 如何在内部网络环境中查看 STS 中的 yml 文件?
- flutter - 从 ListView 中的 textFormField 获取值
- ads - Azure Data Studio Notebook 中连接到 Azure DataWarehouse 的 Python 视觉对象
- html - 确定哪个 DOM 元素导致父元素的尺寸增加