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:
rofl
in sizeof(rofl)
choisit correctement le type rofl
cause des parenthèses? 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.