什么&&当C中没有左侧时,操作员会这样做吗?

时间:2016-09-06 21:09:43

标签: c gcc goto language-extension

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

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

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

我对&&所做的事感到困惑,因为左边没有任何内容。它默认评估为null吗?或者这是一个特例?

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

3 个答案:

答案 0 :(得分:60)

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

作为扩展程序的一部分,goto *ptr;是允许的,其中ptrvoid*类型的表达式。

gcc手册中记录了here

  

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

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

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

goto *ptr;
     

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

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

答案 1 :(得分:16)

这是一个gcc扩展名,称为"标签为值"。 Link to gcc documentation

在此扩展程序中,&&是一个可以应用于标签的一元运算符。结果是类型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

答案 2 :(得分:-6)

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

地址 - 运营商

在左值之前,例如

int j;
int* ptr = &j;

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

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

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

逻辑AND

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

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

按位AND

C中的&符号的另一个用途是执行按位AND。它与逻辑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值参考时放置两个&符号一种。 2)在模板类型或自动扣除类型后放置两个&符号时的通用引用。

我认为您的代码可能仅在您的编译器中编译,因为某些类型的扩展。我在考虑这个https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C,但我怀疑是这样的。