#include <stdio.h>
#include <string.h>
int main(void)
{
char ch='a';
printf("sizeof(ch) = %d\n", sizeof(ch));
printf("sizeof('a') = %d\n", sizeof('a'));
printf("sizeof('a'+'b'+'C') = %d\n", sizeof('a'+'b'+'C'));
printf("sizeof(\"a\") = %d\n", sizeof("a"));
}
Ce programme utilise sizeof
pour calculer les tailles. Pourquoi la taille de 'a'
est-elle différente de celle de ch
(où ch='a'
)?
sizeof(ch) = 1
sizeof('a') = 4
sizeof('a'+'b'+'C') = 4
sizeof("a") = 2
TL; DR - sizeof
fonctionne sur le type de l'opérande.
sizeof(ch)
== sizeof (char)
------------------- (1)sizeof('a')
== sizeof(int)
-------------------- (2)sizeof ('a'+ 'b' + 'c')
== sizeof(int)
--- (3)sizeof ("a")
== sizeof (char [2])
---------- (4)Voyons chaque cas maintenant.
ch
est défini comme étant de type char
, donc assez simple.
En C, sizeof('a')
est identique à sizeof (int)
, dans la mesure où une constante de caractère a un type entier.
Citer C11
,
Une constante de caractère entier a pour type
int
. [...]
En C++, un caractère literal a pour type char
.
sizeof
est un opérateur à la compilation (sauf lorsque l'opérande est un VLA), le type de l'expression est donc utilisé. Comme précédemment, toutes les constantes de caractère entier sont de type int
, donc int
+ int
+ int
produit int
. Le type de l'opérande est donc pris comme int
.
"a"
est un tableau de deux char
s, 'a'
et 0
(terminateur nul) (non, il ne se désactive pas en pointeur vers le premier élément du type de tableau). deux éléments char
.
Cela dit, finalement, sizeof
produit un résultat de type size_t
; vous devez donc utiliser le spécificateur de format %zu
pour imprimer le résultat.
En C, 'a'
est constant de type int
. C'est pas a char
. Donc, sizeof('a')
sera identique à sizeof(int)
.
sizeof(ch)
est identique à sizeof(char)
. (La norme C garantit que toutes les constantes alphanumériques - et quelques autres - de la forme 'a'
peuvent tenir dans une char
, de sorte que char ch='a';
est toujours bien défini.)
Notez qu'en C++, 'a'
est un literal de type char
; encore une autre différence entre C et C++.
En C, sizeof("a")
est sizeof(char[2])
qui est 2. sizeof
n'entraîne pas le decay d'un type de tableau en pointeur.
En C++, sizeof("a")
est sizeof(const char[2])
qui est 2. sizeof
n'entraîne pas le decay d'un type de tableau en pointeur.
Dans les deux langages, 'a'+'b'+'C'
est un type int
en raison, en C++, de la promotion implicite des types intégraux.
Tout d’abord, le résultat de sizeof
est de type size_t
, qui doit être imprimé avec le spécificateur de format %zu
. En ignorant cette partie et en supposant que int
vaut 4 octets, alors
printf("sizeof(ch) %d\n",sizeof(ch));
imprimera 1 en C et 1 en C++.
En effet, il est garanti que char
est d'un octet dans les deux langues.
printf("sizeof('a') %d\n",sizeof('a'));
imprimera 4 en C et 1 en C++.
En effet, les littéraux de caractère sont de type int
en C, pour des raisons historiques1), mais ils sont de type char
en C++, car c’est ce que le sens commun (et ISO 14882) dicte.
printf("sizeof('a'+'b'+'C) %d\n",sizeof('a'+'b'+'C'));
imprimera 4 dans les deux langues.
En C, le type résultant de int + int + int
est naturellement int
. En C++, nous avons char + char + char
. Mais le + invoque les règles de promotion de types implicites nous aboutissons donc à int
à la fin peu importe.
printf("sizeof(\"a\") %d\n",sizeof("a"));
en imprimera 2 dans les deux langues.
La chaîne littérale "a"
est de type char[]
en C et const char[]
en C++. Dans les deux cas, nous avons un tableau composé d'une a
et d'un terminateur nul: deux caractères.
En remarque, cela se produit car le tableau "a"
ne se décompose pas en un pointeur sur le premier élément lorsque l'opérande à sizeof
. Si nous provoquions une dégradation d'un tableau en écrivant par exemple sizeof("a"+0)
, nous aurions plutôt la taille d'un pointeur (probablement 4 ou 8).
1) Quelque part au cours de l’âge sombre, il n’y avait pas de types et tout ce que vous avez écrit se résumerait à int
peu importe. Puis, quand Dennis Ritchie a commencé à cuisiner ensemble une sorte de standard de facto pour C, il a apparemment décidé que les littéraux de caractère devraient toujours être promu à int
. Et plus tard, quand C a été normalisé, ils ont dit que les littéraux de caractères sont simplement int
.
Lors de la création de C++, Bjarne Stroustrup a reconnu que tout cela n’avait pas beaucoup de sens et que les littéraux de caractère devaient taper char
comme ils devraient l’être. Mais le comité C refuse obstinément de corriger ce défaut de langage.
Comme d'autres l'ont mentionné, la norme de langage C définit le type d'une constante de caractère comme étant int
. La raison historique en est que C et son prédécesseur B ont été développés à l’origine sur des mini-ordinateurs DEC PDP avec différentes tailles de Word, qui prenaient en charge le format ASCII à 8 bits, mais ne pouvaient effectuer des opérations arithmétiques que sur les registres. Les premières versions de C définissaient int
comme étant la taille de mot native de la machine et toute valeur inférieure à int
devait être élargie à int
pour pouvoir être transmise à ou depuis une fonction ou utilisée dans une expression binaire, logique ou arithmétique , c’est ainsi que fonctionnait le matériel sous-jacent.
C’est aussi pourquoi les règles de promotion des entiers indiquent toujours que tout type de données inférieur à int
est promu à int
. Les implémentations C sont également autorisées à utiliser les mathématiques complément à complément au lieu de complément à deux pour des raisons historiques similaires, et le fait que le caractère échappe par défaut aux constantes octales et octales commence par juste 0
et que hex requiert \x
ou 0x
, ce qui était le cas pour les mini-ordinateurs du début de DEC. La taille des mots est divisible en morceaux de trois octets, mais pas en quatre octets.
La promotion automatique à int
ne cause que des problèmes aujourd'hui. (Combien de programmeurs savent que multiplier deux expressions uint32_t
constitue un comportement indéfini, car certaines implémentations définissent int
sur une largeur de 64 bits, le langage requiert que tout type de rang inférieur à int
soit promu en signed int
, le résultat de la multiplication de deux multiplicandes int
a le type int
, la multiplication peut déborder d'un produit 64 bits signé, ce qui est un comportement indéfini?) Mais c'est la raison pour laquelle C et C++ sont coincés avec lui.
Je suppose que le code a été compilé en C.
En C, 'a'
est traité comme un type int
et int
a une taille de 4 . En C++, 'a'
est traité comme un type char
et si vous essayez de compiler votre code dans cpp.sh, il devrait renvoyer 1.