当前位置 博文首页 > dadalaohua的博客:【GNU笔记】【C扩展系列】标签作为值

    dadalaohua的博客:【GNU笔记】【C扩展系列】标签作为值

    作者:[db:作者] 时间:2021-07-11 10:07

    【GNU笔记】【C扩展系列】标签作为值 Labels as Values

    标签作为值 Labels as Values

    你可以使用一元运算符“&&”获取当前函数(或包含函数)中定义的标签的地址。值的类型为void *。这个值是一个常量,可以在该类型的常量有效的任何地方使用。例如:

    void *ptr;
    /* … */
    ptr = &&foo;
    

    要使用这些值,你需要能够跳转到一个值。这可以通过计算goto(computed goto)语句1goto *exp;来实现。比如说。

    goto *ptr;
    

    允许使用void*类型的任何表达式。

    使用这些常量的一种方法是初始化用作跳转表的静态数组:

    static void *array[] = { &&foo, &&bar, &&hack };
    

    然后你可以选择一个带有索引的标签,像这样:

    goto *array[i];
    

    请注意,这并不检查下标是否在边界内–C语言中的数组索引从来不会这样做。

    这种标签值数组的用途与switch语句的用途非常相似。switch语句更干净,所以使用它而不是数组,除非问题不适合switch语句。

    标签值的另一个用途是用于线程代码的解释器中。解释器函数中的标签可以存储在线程代码中,以便进行超快速的调度。

    你不能使用这种机制来跳转到不同函数中的代码。如果你这样做,会发生完全不可预测的事情。避免这种情况的最好方法是只将标签地址存储在自动变量中,而绝不将其作为参数传递。

    上述示例的另一种写法是

    static const int array[] = { &&foo - &&foo, &&bar - &&foo,
                                 &&hack - &&foo };
    goto *(&&foo + array[i]);
    

    这对共享库中的代码更友好,因为它减少了所需的动态重定位的数量,因此允许数据为只读。AVR 目标不支持这种带有标签差异的替代方法,请对 AVR 程序使用第一种方法。

    如果包含函数是内联的(inlined)或克隆的(cloned),则同一标签的&&foo表达式可能具有不同的值。如果一个程序依赖于它们总是相同的,那么应该使用__attribute__((__noinline__,__noclone__))来防止内联和克隆。如果在静态变量初始值设定项中使用&&foo,则禁止内联和克隆。


    脚注


    [参考资料]

    6.3 Labels as Values



    1. Fortran 中的类似功能称为分配的 goto(assigned goto),但该名称在C语言中似乎并不合适,在C语言中,人们可以做的不仅仅是将标签地址存储在标签变量中。 ??

    cs