Est-ce que C gère correctement la taille de (…) et la tailleof… dans ce cas?

Dans le code suivant, les fonctions sont-elles test et test2 équivalentes?

 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. Est-ce que rofl in sizeof(rofl) choisit correctement le type rofl cause des parenthèses?
  2. Est-ce que rofl in sizeof *rofl choisit correctement la variable rofl à cause du manque de parenthèses?

Note: Ceci est un exemple idiot, mais dans la pratique, il peut arriver que vous ayez un nom de type identique à un nom de variable. D’où la question.

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

L’opérateur sizeof n’introduit aucun cas particulier pour la recherche de nom. En fait, il n’y a pas de construction de langage qui utilisera la signification cachée d’un identifiant.

En pratique, il est conseillé 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’étiquette, les balises de structure et les membres de structure. Mais dans tous les autres contextes, tous les identificateurs partagent un espace de noms commun: il n’y a pas d’espaces de noms d’identificateurs distincts pour les noms de types par rapport aux noms de variables par rapport aux noms de fonction, etc.

Voici un exemple artificiel:

 typedef int A; // "A" declared as ordinary identifier, meaning a type name struct A { AA; }; // "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 AA(); // "A" declared as ordinary identifier, meaning a function name; hides line 1's A // AC; // Would be error: ordinary A is a function now, not a typedef for int struct AB; // 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 } 

Dans cette déclaration

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

le nom de la variable rofl masque le nom typedef rofl . Ainsi, dans l’opérateur sizeof, le pointeur rofl utilisé est le type int * .

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

 rofl * rofl = malloc(sizeof *rofl); 

sauf qu’il est utilisé une expression avec le pointeur déréférencé rofl qui a le type du nom typedef rofl qui est le type int .

Il semble que la confusion découle de cette définition de la grammaire C.

 sizeof unary-expression sizeof ( type-name ) 

Cependant, l’ unary-expression peut être une expression primaire qui est une expression entre parenthèses.

De la norme C (6.5.1 Expressions primaires)

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

Donc, par exemple, si x est le nom d’une variable, vous pouvez écrire soit

 sizeof x 

ou

 sizeof( x ) 

Pour plus de clarté, vous pouvez insérer des espaces entre l’opérateur sizeof et l’expression primaire

 sizeof ( x ) operator primary expression 

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

 + x 

ou

 + ( x ) 

Maintenant, remplacez simplement le plus unaire par un autre opérateur de sizeof .

En ce qui concerne le masquage des noms, le problème peut être 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 le 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 , de type struct rofl * .

Il n’y a pas de choix ou de choix. Dans les deux cas, le rofl auquel il est fait référence dans chaque sizeof invocation est la variable, et non le type, en raison des règles de scope. La variable est déclarée dans la scope interne et remplace donc le nom du type. La parenthèse de l’argument à l’opérateur sizeof n’est pas pertinente.

Bonne chance.