50 votes

Que fait un opérateur && lorsqu'il n'y a pas de côté gauche en C ?

J'ai vu un programme en C qui avait un code comme le suivant :

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

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

Je suis confus quant à ce que le && 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 ?

Edit : Ajout de quelques informations supplémentaires pour rendre la question/code plus claire pour ma question. Merci à tous pour votre aide. Il s'agissait d'un cas d'extension spécifique à gcc.

60voto

Keith Thompson Points 85120

C'est une extension spécifique à gcc, un unaire. && qui peut être appliqué à un nom d'étiquette, donnant son adresse sous la forme d'un fichier void* valeur.

Dans le cadre de l'extension, goto *ptr; est autorisé lorsque ptr est une expression de type void* .

C'est documenté aquí dans le manuel de gcc.

Vous pouvez obtenir l'adresse d'une étiquette définie dans la fonction courante (ou une fonction qui la contient) avec l'opérateur unaire && . La valeur a type void * . Cette valeur est une constante et peut être utilisée partout où une constante de ce type est valide. constante de ce type est valide. Par exemple :

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

Pour utiliser ces valeurs, vous devez être capable d'en sauter une. Cela se fait avec l'instruction goto calculée, goto *exp; . Par exemple,

goto *ptr;

Toute expression de type void * est autorisé.

Comme le souligne zwol dans un commentaire, gcc utilise && plutôt que le plus évident & parce qu'une étiquette et un objet portant le même nom peuvent être visibles simultanément, ce qui rend &foo potentiellement ambiguë si & signifie "adresse de l'étiquette". Les noms d'étiquettes occupent leur propre espace de noms (pas au sens du C++), et ne peuvent apparaître que dans des contextes spécifiques : définis par un énoncé étiqueté comme la cible d'un goto ou, pour gcc, en tant qu'opérande de l'instruction unaire && .

16voto

Matt McNabb Points 14273

Il s'agit d'une extension de gcc, connue sous le nom de "Labels as Values". Lien vers la documentation de gcc .

Dans cette extension, && est un opérateur unaire qui peut être appliqué à un fichier de type étiquette . Le résultat est une valeur de type void * . Cette valeur peut être déréférencée ultérieurement dans une fonction goto pour que l'exécution saute à cette étiquette. De plus, l'arithmétique des pointeurs est autorisée sur cette valeur.

L'étiquette doit se trouver dans la même fonction ; ou dans une fonction englobante si le code utilise également l'extension gcc des "fonctions imbriquées".

Voici un exemple de programme où la fonction 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

-6voto

Fred Garnier Points 9

Je ne connais pas d'opérateur qui fonctionne de cette façon en C. Selon le contexte, l'esperluette en C peut signifier beaucoup de choses différentes.

Adresse de l'opérateur

Juste avant une lvalue, par exemple

int j;
int* ptr = &j;

Dans le code ci-dessus, ptr stocke l'adresse de j, et dans ce contexte, prend l'adresse de n'importe quelle valeur l. Le code ci-dessous, aurait eu plus de sens pour moi s'il avait été écrit de cette façon.

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

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

ET logique

L'opérateur logique AND est plus simple, contrairement à l'opérateur ci-dessus, c'est un opérateur binaire, ce qui signifie qu'il nécessite un opérande gauche et un opérande droit. Il fonctionne en évaluant les opérandes gauche et droit et en renvoyant true, si les deux sont true, ou plus grand que 0 s'ils ne sont pas bool.

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

ET par bit

Une autre utilisation de l'esperluette en C est l'exécution d'un ET par bit. C'est similaire à l'opérateur logique AND, sauf qu'il n'utilise qu'une seule esperluette et effectue une opération AND au niveau du bit.

Supposons que nous ayons un nombre et qu'il corresponde à la représentation binaire présentée ci-dessous, l'opération ET fonctionne comme suit :

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

Au pays du C++, les choses se compliquent. L'esperluette peut être placée après un type pour désigner un type de référence (on peut la considérer comme une sorte de pointeur moins puissant mais sûr), puis les choses se compliquent encore avec 1) la référence à valeur r lorsque deux esperluettes sont placées après un type. 2) les références universelles lorsque deux esperluettes sont placées après un type modèle ou un type auto-déduit.

Je pense que votre code ne se compile probablement que dans votre compilateur en raison d'une sorte d'extension. Je pensais à ceci https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C mais je doute que ce soit le cas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X