Подтвердить что ты не робот

Что делает оператор &&, когда в C нет левой стороны?

Я видел программу на C, у которой был код вроде следующего:

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

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

Я смущен тем, что делает &&, потому что ничего не осталось от него. Означает ли он по умолчанию значение null? Или это особый случай?

Изменить: Добавлена ​​дополнительная информация, чтобы сделать вопрос/код более понятным для моего вопроса. Спасибо всем за помощь. Это был случай расширения gcc.

4b9b3361

Ответ 1

Это gcc-специфическое расширение, унарный оператор &&, который может быть применен к имени метки, присваивая свой адрес значению void*.

В качестве части расширения допускается goto *ptr;, где ptr - выражение типа void*.

В документе gcc описано здесь.

Вы можете получить адрес метки, определенной в текущей функции (или содержащая функция) с унарным оператором &&. Значение имеет тип void *. Это значение является константой и может использоваться везде, где константа этого типа действительна. Например:

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

Чтобы использовать эти значения, вы должны иметь возможность переходить на один. Готово с вычисленным оператором goto, goto *exp;. Например,

goto *ptr;

Разрешено любое выражение типа void *.

Как отмечает zwol в комментарии, gcc использует &&, а не более очевидный &, потому что метка и объект с тем же именем могут быть видны одновременно, делая &foo потенциально неоднозначным, если & означает "адрес метки". Названия ярлыков занимают собственное пространство имен (не в смысле С++) и могут отображаться только в определенных контекстах: определены с помощью labeled-statement, в качестве цели оператора goto или для gcc, в качестве операнда унарного &&.

Ответ 2

Это расширение gcc, известное как "Ярлыки как значения". Ссылка на документацию gcc.

В этом расширении && является унарным оператором, который может быть применен к метке. Результатом является значение типа 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

Ответ 3

Я не знаю ни одного оператора, который работает таким образом в C. В зависимости от контекста амперсанд в C может означать много разных вещей.

Оператор Address-Of

Прямо перед значением l, например

int j;
int* ptr = &j;

В приведенном выше коде ptr хранится адрес j, и в этом контексте берется адрес любого lvalue. Приведенный ниже код имел бы смысл для меня, если бы он был написан таким образом.

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

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

Логическое И

Логический оператор AND более прост, в отличие от оператора выше, это двоичный оператор, то есть он требует левого и правого операнда. То, как это работает, - это оценить левый и правый операнды и вернуть true, если оба они истинны или больше 0, если они не являются bool.

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

Побитовое И

Другое использование амперсанда в C выполняет побитовое И. Он аналогичен логическому оператору 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

На земле С++ все усложняется. Амперсанд может быть помещен после типа, чтобы обозначить ссылочный тип (вы можете думать о нем как о менее мощном, но безопасном виде указателя), тогда все становится еще сложнее с 1) ссылкой на значение r, когда два амперсанда помещаются после тип. 2) Универсальные ссылки, когда два амперсанда размещаются после типа шаблона или автоматически вычитаемого типа.

Я думаю, что ваш код, вероятно, компилируется только в вашем компиляторе из-за расширения каких-то ролей. Я думал об этом https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C, но я сомневаюсь в этом.