C 中的“本地”标签和跳转表实现

Dr.*_*eon 4 c macros goto jump-table dispatch

我正在尝试用 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:;

}
Run Code Online (Sandbox Code Playgroud)

可能的标签(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:;

    }

}
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?任何可能的解决方法?

PSk*_*cik 8

您需要__label__扩展(至少在 gcc、clang 和 tinycc 中),它允许您将标签范围限定到一个块。

标签需要在块的最开始用

__label__ I0, R0, S0, F0, G0, H0;
Run Code Online (Sandbox Code Playgroud)

(连续__label__ I0; __label__ R0; ...或两种形式的混合也适用。)。

除非用 声明范围局部,否则__label__C 标签的范围仅限于它们的封闭函数。

你的例子__label__

#include "stdio.h"

#define GOTO(X) static void* const caseArg[] = {&&I0, &&R0, &&S0, &&F0, &&G0, &&H0}; \
    goto *caseArg[X];

#define FINISH() goto caseEnd;

#define DECL_LBLS() __label__ I0, R0, S0, F0, G0, H0, caseEnd

int main(int argc, char** argv) {

    {   DECL_LBLS();

        GOTO(2);

        I0: printf("in I0\n"); FINISH();
        R0: printf("in R0\n"); FINISH();
        S0: printf("in S0\n"); FINISH();
        F0: printf("in F0\n"); FINISH();
        G0: printf("in G0\n"); FINISH();
        H0: printf("in H0\n"); FINISH();
        caseEnd:;
    }

    {   DECL_LBLS();

        GOTO(1);

        I0: printf("in I0\n"); FINISH();
        R0: printf("in R0\n"); FINISH();
        S0: printf("in S0\n"); FINISH();
        F0: printf("in F0\n"); FINISH();
        G0: printf("in G0\n"); FINISH();
        H0: printf("in H0\n"); FINISH();
        caseEnd:;
    } 
}
Run Code Online (Sandbox Code Playgroud)

https://gcc.godbolt.org/z/63YSkG

在这种特殊情况下,这种基于本地标签的跳转表似乎比普通的旧switch.