【发布时间】:2020-05-07 17:03:41
【问题描述】:
我正在尝试在 C 中创建一个基于宏的跳转表。
下面是一些示例代码:
#include "stdio.h"
#define GOTO(X) static void* caseArg[] = {&&I0, &&R0, &&S0, &&F0, &&G0, &&H0}; \
goto *caseArg[X];
#define FINISH() goto caseEnd;
int main(int argc, char** argv) {
GOTO(1);
I0: printf("in I0\n"); FINISH();
R0: printf("in R0\n"); FINISH();
S0: printf("in R0\n"); FINISH();
F0: printf("in R0\n"); FINISH();
G0: printf("in R0\n"); FINISH();
H0: printf("in R0\n"); FINISH();
caseEnd:;
}
可能的标签(I0、R0 等)必须相同。
问题是:我希望能够在同一个源文件的不同范围部分中使用同一个宏。但是,编译器抱怨标签已定义。
我想要达到的目标:
int main(int argc, char** argv) {
{ // scope 1
GOTO(1);
I0: printf("in I0\n"); FINISH();
R0: printf("in R0\n"); FINISH();
S0: printf("in R0\n"); FINISH();
F0: printf("in R0\n"); FINISH();
G0: printf("in R0\n"); FINISH();
H0: printf("in R0\n"); FINISH();
caseEnd:;
}
{ // scope 2
GOTO(4);
I0: printf("in I0\n"); FINISH();
R0: printf("in R0\n"); FINISH();
S0: printf("in R0\n"); FINISH();
F0: printf("in R0\n"); FINISH();
G0: printf("in R0\n"); FINISH();
H0: printf("in R0\n"); FINISH();
caseEnd:;
}
}
有什么想法吗?任何可能的解决方法?
【问题讨论】:
-
同一个宏,还是同名的不同宏?
-
如
&&IO中的&&是什么意思? -
对于其他对此感到困惑的人:gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
-
为什么不使用普通的
switch语句? -
@Dr.Kameleon A
switch具有连续的情况应该吐出等效的代码,特别是如果你添加default: __builtin_unreachable();试图哄编译器不要边界检查跳转表。编译器在开关上可能做得更好的一件事是,如果您为共享库编译,它可以将跳转表存储在const存储中并作为偏移量而不是绝对标签。存储偏移量对 PIC 代码更友好(参见 Drepper 的如何编写共享库)。
标签: c macros goto dispatch jump-table