用C99/C11中的预处理器嵌套goto标签?

用C99/C11中的预处理器嵌套goto标签?,c,C,是否可以使用C预处理器在C11或C99中嵌套goto标签?下面的代码可能最能说明我的情况。使用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_(NAM

是否可以使用C预处理器在C11或C99中嵌套goto标签?下面的代码可能最能说明我的情况。使用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.");
    }
}
#包括
//宏,用于损坏标识符以避免冲突
#定义CTX_ID_(名称)上下文_标签35;#名称##_
#定义CTX_ID(名称)CTX_ID(名称)
//context关键字启动一个可以使用break(ID)退出的块;
//只是为了保持它的结构。
#定义上下文(ID)\
if(0){CTX_ID(ID):;}else
//重载break关键字。不妨碍使用普通断路器;
#定义中断(ID)\
do{goto CTX_ID(ID);}while(0)
//示例运行
内部主(空){
上下文(c){
而(1){
放置(“外环,可见”);
而(1){
放置(“内部循环,可见”);
中断(c);
放(“你不会看到我的。”);
}
}
放(“我也不放”);
}
}
我试图去掉标识符(在本例中是c)。但是,与变量不同,goto标签不能嵌套/限定范围,因为它们在函数中必须是唯一的。是否可以在C预处理器中实现唯一的作用域标识符,将其用作goto标签

GCC支持获取标签的地址,但它不是ISO标准的一部分。另外,由于开销和波动性问题,我特别尝试避免setjmp。最后,如果您看不到上述构造的有用性,请考虑进一步的使用,例如try-catch子句或Python风格的表达式,以启用类似RAII的功能。

我相信
\uuu-LINE\uu
宏可能会派上用场。不会有作用域,但至少您可以通过这种方式生成唯一的标签名称


然而,这也不能立即解决您的问题。我要大胆地说,这是无法解决的,尽管我确信有可能有人会来证明我错了

你的想法看起来不错,我唯一想错过的是你的
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
变量很容易被现代编译器优化掉。

不,不幸的是
\uuuline\uuu
不适用于这种情况。该标准不清楚物理源行是什么意思,当宏定义有多行时就会出现这个问题<例如,code>gcc和
clang
为您提供了不同的扩展。但是,我不知道以后如何在代码中重用标签,以便使用goto调用它。在我上面的例子中,
context(c)
的第一行
\uuuu
将计算为某个整数常量n,
break(c)
将计算为n+5。我不明白您为什么不想使用标识符。那么,您将如何确定“中断”的范围?此外,我认为重载关键字并不是一个好主意。对宏使用大写字母(除非它们实际上只是泛型函数接口)是一个很好的惯例。我将更进一步地说,尝试在现有语言的基础上开发一种新的语言,像这样的宏是一项不应该轻率的任务。成本——对不熟悉你的宠物语言的人来说是不可理解的——几乎总是比效用大得多。使用标准gotos编写功能等效代码的成本为零。可能重复感谢。我在提交之前清理了我的代码,在此之前我实际使用了类似于
(void)sizeof(CTX#u ID(ID##ID))
检查控制变量是否存在。@andyn,换句话说,类似于
\u Static\u assert(sizeof(CTX\u ID(ID###ID));
。是的,可能比修改值更好。