是否可以使用C预处理器在C11或C99中嵌套转到标签?通过查看以下代码可能最好地说明了我的情况。使用gcc -std=c99 -pedantic -Wall -Wextra
干净地编译。
#include <stdio.h>
// Macro for mangling the identifier to avoid collisions
#define CTX_ID_(NAME) context_label_ ## NAME ## _
#define CTX_ID(NAME) CTX_ID_(NAME)
// The context keyword starts a block that can be exited with break (ID);
// Just syntactic sugar to keep it structured.
#define context(ID) \
if (0) { CTX_ID(ID): ; } else
// Overloaded break keyword. Doesn't prevent using the plain break;
#define break(ID) \
do { goto CTX_ID(ID); } while (0)
// Example run
int main(void) {
context (c) {
while (1) {
puts("Outer loop, visible.");
while (1) {
puts("Inner loop, visible.");
break (c);
puts("You won't see me.");
}
}
puts("Nor me.");
}
}
我试图取消标识符(在本例中为c)。但是,与变量不同,goto标签不能嵌套/作用域,因为它们必须在函数中是唯一的。是否可以在C预处理器中实现可用作goto标签的唯一作用域标识符?
GCC支持获取标签的地址,但它不是ISO标准的一部分。另外,由于开销和易失性问题,我特意试图避免setjmp。最后,如果您没有看到上述构造的有用性,请考虑进一步使用,如try-catch子句或Python样式的with-expressions,以启用类似RAII的功能。
答案 0 :(得分:2)
我确定 __LINE__
宏可能会派上用场。没有范围,但至少你可以用这种方式生成唯一的标签名称。
然而,这并不是很明显,这也将解决您的问题。我将大胆并声明它不可解决,虽然我确定有可能有人会出现并证明我错了!
答案 1 :(得分:1)
你的想法很好看,我唯一想念的是你的break(c)
可以在函数的任何地方发布。我会在这两个宏中添加类似的东西:
#define CONTEXT(ID) \
if (0) { CTX_ID(ID): ; } \
else for (register bool CTX_ID(ID ## ID) = true; \
CTX_ID(ID ## ID); \
CTX_ID(ID ## ID) = false)
#define BREAK(ID) \
do { \
CTX_ID(ID ## ID) = false; \
goto CTX_ID(ID); \
} while (0)
如果在依赖块之外使用BREAK(c)
,则会导致语法错误。根据我的经验,这里使用的for
变量很容易被现代编译器优化掉。