当实现C标准的Annex K(Bounds-checking Interfaces)时,有以下要求:
通过将__STDC_WANT_LIB_EXT1__
定义为1
,可以“请求”声明此附录中指定的扩展,并通过将其定义为0
来请求不声明。
然后有这段话:
在预处理翻译单元中,对于从子句K.3包含的任何头文件的所有包含,__STDC_WANT_LIB_EXT1_ _必须被定义为相同。 如果对于任何这样的包含__STDC_WANT_LIB_EXT1_ _被定义为不同,则实现应发出一条诊断,就像使用了预处理器错误指令一样。
我想知道如何实现这个要求。 我继续天真地编写了以下内容(以包含每个受影响的头文件):
#ifndef __STDC_WANT_LIB_EXT1__
#ifdef __STDC_WANT_LIB_EXT1_PREVIOUS__
#error __STDC_WANT_LIB_EXT1__ undefined when it was defined previously.
#endif
#else
#ifdef __STDC_WANT_LIB_EXT1_PREVIOUS__
#if __STDC_WANT_LIB_EXT1__ != __STDC_WANT_LIB_EXT1_PREVIOUS__
#error __STDC_WANT_LIB_EXT1__ defined to different value from previous include.
#endif
#else
#define __STDC_WANT_LIB_EXT1_PREVIOUS__ __STDC_WANT_LIB_EXT1__
#endif
#endif
当然,这种方法由于多种原因是不可行的:
- 无法捕获第一个include未定义__STDC_WANT_LIB_EXT1__但第二个include定义了该值的情况(应该使用#error捕获)
#define
没有考虑到__STDC_WANT_LIB_EXT1__
的值(在前面加上#
会将符号作为字符串,通过symbol2value(...)会将1
作为字符串)。- ...
...但如果将其视为伪代码,则可以展示其背后的逻辑。
我对这种更为复杂的预处理器操作并不熟悉,因为通常会被告知避免使用宏魔法。 一定有一种实现引用要求的方法;只是我还没有“想到”。
有什么想法吗?
要完成[mcve],将上述代码放入header.h
,并将以下内容放入testme.c
:
#define __STDC_WANT_LIB_EXT1__ 0
#include "header.h"
#define __STDC_WANT_LIB_EXT1__ 1
#include "header.h"
int main() {}
这个应该会触发“不同值”错误信息。
0
、1
或某个标记(我们将说为-1
表示未定义)。宏不是变量;它们存储替换列表,而不是该替换列表将扩展到什么,特别是在这里,您希望您的存储确切地是您找到的内容(这样下次定义“EXT”时,您不会简单地认为您等于它)。 - H Walters#define PREV CURRENT
是一个陷阱;当定义为1时并不重要...一旦在第二个包含中将CURRENT定义为0并且此宏用作值时,它将扩展为0。你需要#if CURRENT==1/#define PREV 1
;这样,如果CURRENT
被重新定义为0并且与PREV进行比较,它将真正不相等。 - H Walters