Reputation: 70263
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:
__STDC_WANT_LIB_EXT1__
is not defined for the first include, but defined for the second (which should also be caught with an #error
)#define
does not take the value of __STDC_WANT_LIB_EXT1__
(prefixing #
would take the symbol as string, going through symbol2value(...) would take the 1
as 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.
Upvotes: 4
Views: 216
Reputation: 70263
@HWalters did set me on the right track:
#ifndef __STDC_WANT_LIB_EXT1__
#ifdef __STDC_WANT_LIB_EXT1_PREVIOUS__
#if __STDC_WANT_LIB_EXT1_PREVIOUS__ != -1
#error __STDC_WANT_LIB_EXT1__ undefined when it was defined earlier.
#endif
#else
#define __STDC_WANT_LIB_EXT1_PREVIOUS__ -1
#endif
#else
#ifdef __STDC_WANT_LIB_EXT1_PREVIOUS__
#if __STDC_WANT_LIB_EXT1__ != __STDC_WANT_LIB_EXT1_PREVIOUS__
#error __STDC_WANT_LIB_EXT1__ redefined from previous value.
#endif
#else
#if __STDC_WANT_LIB_EXT1__ == 0
#define __STDC_WANT_LIB_EXT1_PREVIOUS__ 0
#elif __STDC_WANT_LIB_EXT1__ == 1
#define __STDC_WANT_LIB_EXT1_PREVIOUS__ 1
#else
/* Values other than 0,1 reserved for future use */
#define __STDC_WANT_LIB_EXT1_PREVIOUS__ -2
#endif
#endif
#endif
The "thinko" was this line:
#define __STDC_WANT_LIB_EXT1_PREVIOUS__ __STDC_WANT_LIB_EXT1__
Defining the "previous" to an actual value instand of another token makes it work.
The solution is not perfect, though -- all "other" values except 0,1,undefined get lumped together into a single "previous" value (-2), while the letter of the standard says that any redefinition should issue a diagnostic.
Upvotes: 4