38 votes

Le C gère-t-il correctement sizeof(...) et sizeof ... dans ce cas ?

Dans le code suivant, se trouvent les fonctions test y test2 équivalent ?

typedef int rofl;

void test(void) {
    rofl * rofl = malloc(sizeof(rofl)); // Is the final rofl here the TYPE?
}

void test2(void) {
    rofl * rofl = malloc(sizeof *rofl); // Is the final rofl here the VARIABLE?
}

En d'autres termes :

  1. Fait rofl en sizeof(rofl) choisir correctement le rofl type à cause des parenthèses ?
  2. Fait rofl en sizeof *rofl choisir correctement le rofl variable à cause d'un absence de de parenthèses ?

Note : Il s'agit d'un exemple d'apparence stupide, mais il peut arriver dans la pratique que le nom d'un type soit identique à celui d'une variable. D'où la question.

27voto

Matt McNabb Points 14273

Dans les deux cas, le dernier rofl est le nom de la variable. Un nom de variable est dans la portée dès qu'il apparaît ; et pour le reste de la portée courante, cet identifiant dans un contexte ordinaire(*) signifie toujours le nom de la variable.

En sizeof n'introduit aucun cas particulier pour la recherche de noms. En fait, il n'existe aucune construction de langage qui utilisera le sens caché d'un identifiant.

En pratique, il est bon de ne pas utiliser le même identifiant pour un type et un nom de variable.


(*) Il existe trois contextes spéciaux pour les identificateurs : les noms d'étiquettes, les balises de structure et les membres de structure. Mais dans tous les autres contextes, tous les identificateurs partagent un espace de nom commun : il n'existe pas d'espaces de nom d'identificateur distincts pour les noms de type, les noms de variable, les noms de fonction, etc.

Voici un exemple artificiel :

typedef int A;      // "A" declared as ordinary identifier, meaning a type name

struct A { A A; };  // "A" declared as struct tag and member name -- OK as these are three different name spaces. Member type is "int"

A main()            // int main() - ordinary context
{
    struct A A();   // "A" declared as ordinary identifier, meaning a function name; hides line 1's A
    // A C;         // Would be error: ordinary A is a function now, not a typedef for int
    struct A B;     // OK, struct tags have separate name space
    A:+A().A;       // OK, labels and struct members have separate name space, calls function
    goto A;         // OK, label name space
}

13voto

Vlad from Moscow Points 36219

Dans cette déclaration

rofl * rofl = malloc(sizeof(rofl)); // Is the final rofl here the TYPE?

le nom de la variable rofl cache le nom du typedef rofl . Ainsi, dans l'opérateur sizeof, on utilise le pointeur rofl c'est-à-dire que l'expression a le type int * .

La même chose est valable pour cette déclaration

rofl * rofl = malloc(sizeof *rofl); 

sauf que l'on utilise une expression avec le pointeur déréférencé rofl qui a le type du nom typedef rofl c'est-à-dire le type int .

Il semble que la confusion soit due à cette définition de la grammaire C.

sizeof unary-expression
sizeof ( type-name )

Cependant unary-expression peut être une expression primaire, c'est-à-dire une expression entre parenthèses.

Extrait de la norme C (6.5.1 Expressions primaires)

primary-expression:
    ( expression )
    //...

Ainsi, par exemple, si x est le nom d'une variable, vous pouvez alors écrire soit

sizeof x 

o

sizeof( x )

Pour plus de clarté, vous pourriez insérer des blancs entre l'opérateur sizeof et l'expression primaire

sizeof    ( x )
operator  primary expression

À titre de comparaison, considérons un autre opérateur unaire : le plus unaire. Vous pouvez écrire par exemple

+ x

o

+ ( x )

Maintenant, il suffit de remplacer le plus unaire par un autre opérateur unaire. sizeof .

En ce qui concerne la dissimulation des noms, le problème est résolu pour les structures, les unions et les énumérations car leurs noms incluent des mots-clés pour les balises.

Par exemple

typedef struct rofl { int x; } rofl;

void test(void) {
    rofl * rofl = malloc(sizeof( struct rofl));
}

Dans cette fonction, avec l'opérateur sizeof, on utilise un nom de type struct rofl .

Dans cette fonction

typedef struct rofl { int x; } rofl;

void test(void) {
    rofl * rofl = malloc(sizeof( rofl));
}

avec l'opérateur sizeof, on utilise une expression primaire avec la variable rofl qui a le type struct rofl * .

2voto

Bob Jarvis Points 14906

Il n'y a pas de "sélection" ou de "choix". Dans les deux cas, le rofl visés dans chaque sizeof L'invocation est la variable, et non le type, en raison des règles de scoping. La variable est déclarée à l'intérieur de la portée, et remplace donc le nom du type. La mise entre parenthèses de l'argument de la méthode sizeof n'est pas pertinent.

Bonne chance.

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