使用C预处理器确定当前范围?

时间:2012-08-20 15:12:40

标签: scope global-variables clang static-variables nested-function

我正在用C / Objective-C开发一个应用程序(请不要使用C ++,我已经有了解决方案),我遇到了一个有趣的用例。

因为clang不支持嵌套函数,所以我原来的方法不起作用:

#define CREATE_STATIC_VAR(Type, Name, Dflt) static Type Name; __attribute__((constructor)) void static_ ## Type ## _ ## Name ## _init_var(void) { /* loading code here */ }

这段代码可以用GCC编译好,但由于clang不支持嵌套函数,我收到编译错误:

  

预期';'在宣言结束时。

所以,我找到了一个适用于Clang函数内部变量的解决方案:

#define CREATE_STATIC_VAR_LOCAL(Type, Name, Dflt) static Type Name; ^{ /* loading code here */ }(); // anonymous block usage

但是,我想知道是否有办法利用宏连接为情况选择合适的方法,例如:

#define CREATE_STATIC_VAR_GLOBAL(Type, Name, Dflt) static Type Name; __attribute__((constructor)) void static_ ## Type ## _ ## Name ## _init_var(void) { /* loading code here */ }
#define CREATE_STATIC_VAR_LOCAL(Type, Name, Dflt) static Type Name; ^{ /* loading code here */ }(); // anonymous block usage

#define SCOPE_CHOOSER LOCAL || GLOBAL
#define CREATE_STATIC_VAR(Type, Name, DFLT) CREATE_STATIC_VAR_ ## SCOPE_CHOOSER(Type, Name, Dflt)

显然,结束实现并不一定非如此,但类似的东西就足够了。

我曾尝试将__builtin_constant_p__func__一起使用,但由于__func__不是编译时常量,因此无效。

我也尝试使用__builtin_choose_expr,但这似乎不适用于全球范围。

文档中是否还有其他内容?看起来这应该是相当容易做的事情,然而,我似乎无法弄明白。

注意: 我知道我只需输入CREATE_STATIC_VAR_GLOBALCREATE_STATIC_VAR_LOCAL,而不是搞乱宏连接,但这是我试图突破编译器的极限。我也知道我可以使用C ++并立即解决这个问题,但这不是我的目标。

1 个答案:

答案 0 :(得分:1)

#define SCOPE_CHOOSER LOCAL || GLOBAL
#define CREATE_STATIC_VAR(Type, Name, DFLT) CREATE_STATIC_VAR_ ## SCOPE_CHOOSER(Type, Name, Dflt)

这里最大的困难是C预处理器通过文本替换来工作,所以即使你想出如何让SCOPE_CHOOSER做你想做的事情,你最终会得到一个看似像

CREATE_STATIC_VAR_LOCAL || GLOBAL(Type, Name, Dflt);

在替换过程中无法使预处理器进行“常数折叠”宏扩展;事物被“折叠”的唯一时间是它们出现在#if表达式中。所以你唯一的希望(模数轻微的手工操作)就是找到一个可以在函数内外工作的结构。

你能解释一下这里的最终目标吗?我不认为您可以使用__attribute__((constructor))加载变量的初始值,但是可能有一种方法可以在第一次输入函数体时加载初始值...或者将这些变量的所有地址注册到编译时的全局列表,并且有一个遍历该列表的__attribute__((constructor))函数...或者这些方法的一些混乱。我没有任何具体的想法,但也许如果你提供更多的信息会出现一些东西。

编辑: 我不认为这对你有帮助,因为它不是预处理器技巧,但这里有一个常量表达式,在函数范围内计算为0,在全球范围。

#define AT_GLOBAL_SCOPE __builtin_types_compatible_p(const char (*)[1], __typeof__(&__func__))

然而,请注意我说“评估”而不是“扩展”。这些构造是编译时,而不是预处理时间。