[英]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.