What does a && operator do when there is no left side in C?
It's a gcc-specific extension, a unary &&
operator that can be applied to a label name, yielding its address as a void*
value.
As part of the extension, goto *ptr;
is allowed where ptr
is an expression of type void*
.
It's documented here in the gcc manual.
You can get the address of a label defined in the current function (or a containing function) with the unary operator
&&
. The value has typevoid *
. This value is a constant and can be used wherever a constant of that type is valid. For example:
void *ptr;/* ... */ptr = &&foo;
To use these values, you need to be able to jump to one. This is done with the computed goto statement,
goto *exp;
. For example,
goto *ptr;
Any expression of type
void *
is allowed.
As zwol points out in a comment, gcc uses &&
rather than the more obvious &
because a label and an object with the same name can be visible simultaneously, making &foo
potentially ambiguous if &
means "address of label". Label names occupy their own namespace (not in the C++ sense), and can appear only in specific contexts: defined by a labeled-statement, as the target of a goto
statement, or, for gcc, as the operand of unary &&
.
This is a gcc extension, known as "Labels as Values". Link to gcc documentation.
In this extension, &&
is a unary operator that can be applied to a label. The result is a value of type void *
. This value may later be dereferenced in a goto
statement to cause execution to jump to that label. Also, pointer arithmetic is permitted on this value.
The label must be in the same function; or in an enclosing function in case the code is also using the gcc extension of "nested functions".
Here is a sample program where the feature is used to implement a state machine:
#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; }}
Compiling and execution:
$ gcc -o x x.c && ./xFooQuxFooQuxBarFooQuxQuxBarFoo
I'm not aware of any operator that works this way in C. Depending on the context, the ampersand in C can mean many different things.
Address-Of operator
Right before an lvalue, e.g.
int j;int* ptr = &j;
In the code above, ptr stores the address of j, & in this context is taking the address of any lvalue. The code below, would have made more sense to me if it was written that way.
static int varOne;static int varTwo;static int varThree;static void *arr[1][8432] = { { &varOne,&varTwo, &varThree } };
Logical AND
The logical AND operator is more simple, unlike the operator above, it's a binary operator, meaning it requires a left and right operand. The way it works is by evaluating the left and right operand and returning true, iff both are true, or greater than 0 if they are not bool.
bool flag = true;bool flag2 = false;if (flag && flag2) { // Not evaluated}flag2 = true;if (flag && flag2) { // Evaluated}
Bitwise AND
Another use of the ampersand in C, is performing a bitwise AND. It's similar as the logical AND operator, except it uses only one ampersand, and performs an AND operation at the bit level.
Let's assume we have a number and that it maps to the binary representation shown below, the AND operation works like so:
0 0 0 0 0 0 1 01 0 0 1 0 1 1 0---------------0 0 0 0 0 0 1 0
In C++ land, things get more complicated. The ampersand can be placed after a type as to denote a reference type (you can think of it as a less powerful but safe kind of pointer), then things get even more complicated with 1) r-value reference when two ampersands are placed after a type. 2) Universal references when two ampersands are placed after a template type or auto deducted type.
I think your code probably compiles only in your compiler due to an extension of some sorts. I was thinking of this https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C but I doubt that's the case.