一次性使用后取消定义宏内的常量

Undefining constant inside macro after single use

我想要一个宏,它会在调用时取消定义传递给它的常量。 像这样:

#define CONSTANT1 123

#define macro(const) \
#ifdef const \
const \
#undef const \
#else \
#error "constant already used once" \
#endif

int main(){
int a = macro(CONSTANT1); // a = 123
int b = macro(CONSTANT1); // <- preprocessor error "constant already used once"
return 0;
}

是否可以使用预处理器存档此功能?

我认为使用标准 C 预处理器无法获得它,但可以使用 GCC/CLANG 编译指示,如 push_macro/pop_macro:

// define a macro that will generate error on expansion
#define CONSTANT1 _Pragma("GCC error \"CONSTANT1 expanded more than once\"")

// save this macro and undefine it
#pragma push_macro("CONSTANT1")
#undef CONSTANT1

// let CONSTANT1 expand to 123, but replace with
// previous error-generation macro 
#define CONSTANT1 123 _Pragma("pop_macro(\"CONSTANT1\")") 


int a = CONSTANT1;
int b = CONSTANT1;

使用 gcc/clang 编译生成:

prog.c:8:11: error: CONSTANT1 expanded more than once
    8 | int b = CONSTANT1;

请注意,pragmas push_macro/pop_macro 非常便携,GCC、CLANG、MSVS 和 Intel C 编译器都支持它们。

失败 CONSTANT1 的更便携版本可能是:

#define CONSTANT1 sizeof(struct {_Static_assert(0, "CONSTANT1 expanded more than once"); int x; })

它需要 C11 兼容的编译器。