簡體   English   中英

在C99 / C11中使用預處理器嵌套goto標簽?

[英]Nesting goto labels with the preprocessor in C99/C11?

是否可以使用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的功能。

我確信 __LINE__宏可能會派上用場。 沒有范圍,但至少你將能夠以這種方式生成唯一的標簽名稱。

然而,這並不是很明顯,這也將解決您的問題。 我會大膽地說它不可解決,雖然我確信有可能會有人來證明我錯了!

你的想法很好看,我唯一想念的是你的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這里使用的變量很容易被現代的編譯器優化掉。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM