50

我在 C 中看到一个程序,其代码如下:

static void *arr[1]  = {&& varOne,&& varTwo,&& varThree};

varOne: printf("One") ;
varTwo: printf("Two") ;
varThree: printf("Three") ;

我对它的作用感到困惑,&&因为它的左边没有任何东西。默认情况下它是否评估为空?或者这是一个特例?

编辑:添加了更多信息,以使问题/代码对我的问题更加清晰。谢谢大家的帮助。这是 gcc 特定扩展的一个案例。

4

3 回答 3

62

这是一个 gcc 特定的扩展,一个&&可以应用于标签名称的一元运算符,将其地址作为void*值产生。

作为扩展的一部分,goto *ptr;允许 whereptr是 type 的表达式void*

它记录gcc 手册中。

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

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

要使用这些值,您需要能够跳转到一个。这是通过计算的 goto 语句完成的goto *exp;。例如,

goto *ptr;

任何类型的表达式void *都是允许的。

正如 zwol 在评论中指出的那样,gcc 使用&&而不是更明显&的,因为标签和具有相同名称的对象可以同时可见,如果意味着“标签的地址” ,&foo则可能会产生歧义。&标签名称占据它们自己的命名空间(不是 C++ 意义上的),并且只能出现在特定的上下文中:由label-statement定义,作为语句的目标goto,或者对于 gcc,作为 unary 的操作数&&

于 2016-09-07T00:03:06.793 回答
18

这是一个 gcc 扩展,称为“标签即值”。链接到 gcc 文档

在这个扩展中,&&是一个可以应用于标签的一元运算符。结果是 type 的值void *。稍后可能会在goto语句中取消引用此值以导致执行跳转到该标签。此外,允许对该值进行指针运算。

标签必须在同一个函数中;或者在封闭函数中,以防代码也使用“嵌套函数”的 gcc 扩展。

这是一个示例程序,其中该功能用于实现状态机:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
    void *tab[] = { &&foo, &&bar, &&qux };

    // Alternative method
    //ptrdiff_t otab[] = { &&foo - &&foo, &&bar - &&foo, &&qux - &&foo };

    int i, state = 0;

    srand(time(NULL));

    for (i = 0; i < 10; ++i)
    {
        goto *tab[state];

        //goto *(&&foo + otab[state]);

    foo:
        printf("Foo\n");
        state = 2;
        continue;
    bar:
        printf("Bar\n");
        state = 0;
        continue;
    qux:
        printf("Qux\n");
        state = rand() % 3;
        continue;
    }
}

编译和执行:

$ gcc -o x x.c && ./x
Foo
Qux
Foo
Qux
Bar
Foo
Qux
Qux
Bar
Foo
于 2016-09-07T00:03:45.320 回答
-7

我不知道有任何运算符在 C 中以这种方式工作。根据上下文,C 中的 & 符号可能意味着许多不同的东西。

地址操作符

就在左值之前,例如

int j;
int* ptr = &j;

在上面的代码中,ptr存储 j 的地址,& 在此上下文中获取任何左值的地址。如果以这种方式编写,下面的代码对我来说会更有意义。

static int varOne;
static int varTwo;
static int varThree;

static void *arr[1][8432] = { { &varOne,&varTwo, &varThree } };

逻辑与

逻辑 AND 运算符更简单,与上面的运算符不同,它是一个二元运算符,这意味着它需要一个左右操作数。它的工作方式是通过评估左右操作数并返回 true,如果两者都是 true,或者如果它们不是 bool,则大于 0。

bool flag = true;
bool flag2 = false;
if (flag && flag2) {
    // Not evaluated
}
flag2 = true;
if (flag && flag2) {
   // Evaluated
}

按位与

C 中与符号的另一种用法是执行按位与。它类似于逻辑 AND 运算符,不同之处在于它只使用一个 & 符号,并在位级别执行 AND 运算。

假设我们有一个数字,并且它映射到如下所示的二进制表示,AND 操作的工作方式如下:

0 0 0 0 0 0 1 0
1 0 0 1 0 1 1 0
---------------
0 0 0 0 0 0 1 0

在 C++ 领域,事情变得更加复杂。& 符号可以放在类型之后以表示引用类型(您可以将其视为一种功能较弱但安全的指针),然后事情变得更加复杂 1)当两个 & 符号放在后面时,r-value 引用一种。2)当两个&符号放在模板类型或自动扣除类型之后时的通用引用。

我认为由于某种扩展,您的代码可能仅在您的编译器中编译。我在想这个https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C但我怀疑是这样。

于 2016-09-06T21:50:46.590 回答