我正在用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_GLOBAL
或CREATE_STATIC_VAR_LOCAL
,而不是搞乱宏连接,但这是我试图突破编译器的极限。我也知道我可以使用C ++并立即解决这个问题,但这不是我的目标。
答案 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__))
然而,请注意我说“评估”而不是“扩展”。这些构造是编译时,而不是预处理时间。