When implementing Annex K of the C standard (Bounds-checking Interfaces), there is the following requirement:
The extensions specified in this annex can be "requested" to be declared by defining __STDC_WANT_LIB_EXT1__ to 1, and requested to not be declared by defining that to 0.
Then there is this paragraph:
Within a preprocessing translation unit, __STDC_WANT_LIB_EXT1_ _ shall be defined identically for all inclusions of any headers from subclause K.3. If __STDC_WANT_LIB_EXT1_ _ is defined differently for any such inclusion, the implementation shall issue a diagnostic as if a preprocessor error directive were used.
I wonder how to implement this. I went ahead and naïvely wrote this (to be included in each affected header):
#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
This (of course) does not work for a variety of reasons:
- Does not catch the case when
__STDC_WANT_LIB_EXT1__is not defined for the first include, but defined for the second (which should also be caught with an#error) - The
#definedoes not take the value of__STDC_WANT_LIB_EXT1__(prefixing#would take the symbol as string, going through symbol2value(...) would take the1as string). - ...
...but if taken as pseudocode it showcases the logic behind it.
I am not that well-versed with more intricate preprocessor business like this, as you are usually told to stay away from macro magic. There has to be a way to implement the quoted requirement; it just doesn't "click" for me.
Any ideas?
To complete the [mcve], put the above code into header.h, and this in testme.c:
#define __STDC_WANT_LIB_EXT1__ 0
#include "header.h"
#define __STDC_WANT_LIB_EXT1__ 1
#include "header.h"
int main() {}
This should trigger the "different value" error message.
#undefas well. Could we please focus on the topic of the question instead of discussing code style of the example?PREVIOUSmacro in terms of the current value; define it as literally0,1, or some token (-1we'll say to represent undefined). Macros aren't variables; they store replacement lists, not what that replacement list would expand to, and especially here you want your storage to be literally what you found (so that next time theEXTis defined, you don't simply think you're equal to it).#define PREV CURRENTis a trap; thatCURRENTis 1 when the definition is made is of no consequence... once CURRENT is defined as 0 for the second include and this macro is used as a value, it will expand to 0. You want#if CURRENT==1/#define PREV 1; this way, ifCURRENTis redefined to 0 and you compare to PREV, it will truly be not equal.