J'ai vu un programme en C qui avait du code comme celui-ci:
static void *arr[1] = {&& varOne,&& varTwo,&& varThree};
varOne: printf("One") ;
varTwo: printf("Two") ;
varThree: printf("Three") ;
Je suis confus sur ce que le &&
le fait parce qu'il n'y a rien à sa gauche. Est-il évalué comme nul par défaut? Ou s'agit-il d'un cas particulier?
Modifier: Ajout de plus d'informations pour rendre la question/le code plus clair pour ma question. Merci à tous pour l'aide. C'était le cas de l'extension spécifique à gcc.
C'est une extension spécifique à gcc, un opérateur unaire &&
Qui peut être appliqué à un nom d'étiquette, donnant son adresse sous la forme d'une valeur void*
.
Dans le cadre de l'extension, goto *ptr;
Est autorisé où ptr
est une expression de type void*
.
C'est documenté ici dans le manuel de gcc.
Vous pouvez obtenir l'adresse d'une étiquette définie dans la fonction courante (ou une fonction contenante) avec l'opérateur unaire
&&
. La valeur a le typevoid *
. Cette valeur est une constante et peut être utilisée partout où une constante de ce type est valide. Par exemple:void *ptr; /* ... */ ptr = &&foo;
Pour utiliser ces valeurs, vous devez pouvoir passer à une. Cela se fait avec l'instruction goto calculée,
goto *exp;
. Par exemple,goto *ptr;
Toute expression de type
void *
Est autorisée.
Comme zwol le fait remarquer dans un commentaire, gcc utilise &&
Plutôt que le plus évident &
Car une étiquette et un objet du même nom peuvent être visibles simultanément, ce qui rend &foo
Potentiellement ambigu si &
signifie "adresse de l'étiquette". Les noms d'étiquette occupent leur propre espace de nom (pas dans le sens C++) et ne peuvent apparaître que dans des contextes spécifiques: définis par une étiquette-déclaration , comme cible d'une instruction goto
, ou, pour gcc, comme l'opérande d'unaire &&
.
Il s'agit d'une extension gcc, connue sous le nom de "Labels as Values". Lien vers la documentation gcc .
Dans cette extension, &&
est un opérateur unaire qui peut être appliqué à une étiquette . Le résultat est une valeur de type void *
. Cette valeur peut être déréférencée ultérieurement dans une instruction goto
pour provoquer l'exécution de sauter à cette étiquette. De plus, l'arithmétique des pointeurs est autorisée sur cette valeur.
L'étiquette doit avoir la même fonction; ou dans une fonction englobante au cas où le code utilise également l'extension gcc de "fonctions imbriquées".
Voici un exemple de programme où la fonctionnalité est utilisée pour implémenter une machine à états:
#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;
}
}
Compilation et exécution:
$ gcc -o x x.c && ./x
Foo
Qux
Foo
Qux
Bar
Foo
Qux
Qux
Bar
Foo