web-dev-qa-db-fra.com

Pourquoi "sizeof (a? True: false)" donne une sortie de quatre octets?

J'ai un petit morceau de code sur l'opérateur sizeof avec l'opérateur ternaire:

#include <stdio.h>
#include <stdbool.h>

int main()
{
    bool a = true;
    printf("%zu\n", sizeof(bool));  // Ok
    printf("%zu\n", sizeof(a));     // Ok
    printf("%zu\n", sizeof(a ? true : false)); // Why 4?
    return 0;
}

Sortie ( GCC ):

1
1
4 // Why 4?

Mais ici,

printf("%zu\n", sizeof(a ? true : false)); // Why 4?

l'opérateur ternaire retourne boolean type et sizeof bool le type est 1 octet en C.

Alors pourquoi sizeof(a ? true : false) donne-t-il une sortie de quatre octets?

131
msc

C'est parce que vous avez #include <stdbool.h>. Cet en-tête définit les macrostrue et false doit être 1 et 0, ainsi votre déclaration se présente comme suit:

printf("%zu\n", sizeof(a ? 1 : 0)); // Why 4?

sizeof(int) est égal à 4 sur votre plate-forme.

224
Justin

Ici, l'opérateur ternaire renvoie boolean type,

OK, il y a plus que ça!

En C, le résultat de l'opération this est de type int[notes ci-dessous (1,2)]

Le résultat est donc le même que l'expression sizeof(int), sur votre plate-forme.


Note 1: Citation de C11, chapitre §7.18, Boolean type and values <stdbool.h>

[....] Les trois macros restantes peuvent être utilisées dans les directives de pré-traitement #if. Elles sont

true

qui se développe à la constante entière 1,

false

qui se développe à la constante entière 0, [....]

Note 2: Pour l'opérateur conditionnel, chapitre §6.5.15, ( l'emphase mine )

Le premier opérande est évalué. il y a un point de séquence entre son évaluation et l'évaluation du deuxième ou du troisième opérande (selon l'évaluation). Le deuxième opérande est évalué uniquement si le premier est différent de 0; le troisième opérande est évalué uniquement si le premier compare égal à 0; le résultat est la valeur du deuxième ou du troisième opérande (selon l'évaluation), [...]

et

Si les deuxième et troisième opérandes ont tous deux un type arithmétique, le type de résultat qui serait déterminé par les conversions arithmétiques habituelles, s’ils étaient appliqués à ces deux opérandes, est le type du résultat. [... .]

par conséquent, le résultat sera de type entier et, en raison de la plage de valeurs, les constantes sont précisément de type int.

Cela dit, un conseil générique, int main() devrait mieux être int main (void) pour être vraiment conforme aux normes.

67
Sourav Ghosh

L'opérateur ternaire est un hareng rouge.

    printf("%zu\n", sizeof(true));

affiche 4 (ou tout ce que sizeof(int) se trouve sur votre plate-forme).

Ce qui suit suppose que bool est un synonyme de char ou d'un type similaire de taille 1 et que int est supérieur à char.

La raison pour laquelle sizeof(true) != sizeof(bool) et sizeof(true) == sizeof(int) est simplement parce que true est not une expression de type bool. C'est une expression de type int. C'est #defined comme 1 dans stdbool.h.

Il n'y a pas du tout de rvalues ​​de type bool en C. Chacune de ces valeurs est immédiatement promue en int, même si elle est utilisée comme argument pour sizeof. Edit: ce paragraphe n’est pas vrai, les arguments de sizeof ne sont pas promus en int. Cela n'affecte cependant aucune des conclusions.

58
n.m.

Concernant le type booléen en C

Un type booléen a été introduit assez tard dans le langage C, en 1999. Avant cela, C n'avait pas de type booléen mais utilisait plutôt int pour toutes les expressions booléennes. Par conséquent, tous les opérateurs logiques tels que > == ! etc. renvoient un int de valeur 1 ou 0.

Il était courant que les applications utilisent des types faits maison tels que typedef enum { FALSE, TRUE } BOOL;, qui se résume également à des types de la taille int.

C++ avait un type booléen bien meilleur et explicite, bool, qui n'était pas plus grand qu'un octet. Alors que les types ou expressions booléens en C finiraient par 4 octets dans le pire des cas. Une certaine compatibilité avec C++ a été introduite dans C avec le standard C99. C a ensuite reçu un type booléen _Bool ainsi que l'en-tête stdbool.h.

stdbool.h fournit une certaine compatibilité avec C++. Cet en-tête définit la macro bool (même orthographe que le mot clé C++) qui se développe en _Bool, un type qui est un type entier petit, probablement 1 octet important. De même, l'en-tête fournit deux macros true et false, la même orthographe que les mots clés C++, mais avec une compatibilité ascendante avec les programmes C plus anciens . Par conséquent, true et false sont développés en 1 et 0 en C et leur type est int. Ces macros ne sont pas réellement du type booléen comme le seraient les mots-clés C++ correspondants.

De même, pour des raisons de compatibilité ascendante, les opérateurs logiques de C still retournent un int à ce jour, même si C a de nos jours un type booléen. En C++, les opérateurs logiques renvoient un bool. Ainsi, une expression telle que sizeof(a == b) donnera la taille d'un int en C, mais la taille d'un bool en C++.

En ce qui concerne l'opérateur conditionnel ?:

L'opérateur conditionnel ?: est un opérateur étrange avec quelques bizarreries. C'est une erreur courante de croire que c'est l'équivalent de if() { } else {} à 100%. Pas assez.

Il y a un point de séquence entre l'évaluation du premier et du deuxième ou du troisième opérande. Il est garanti que l'opérateur ?: évalue uniquement le deuxième ou le troisième opérande, de sorte qu'il ne peut exécuter aucun effet secondaire de l'opérande non évalué. Un code tel que true? func1() : func2() n'exécutera pas func2(). Jusqu'ici tout va bien.

Cependant , il existe une règle spéciale stipulant que les 2ème et 3ème opérandes doivent être implicitement dactylographiés et comparés les uns aux autres avec les conversions arithmétiques usuelles . ( Règles de promotion de type implicites en C expliquées ici ). Cela signifie que le 2ème ou le 3ème opérande sera toujours toujours au moins égal à int.

Ainsi, peu importe que true et false soient de type int en C car l'expression donnerait toujours au moins la taille d'un int, peu importe.

Même si vous réécriviez l'expression en sizeof(a ? (bool)true : (bool)false) il retournera toujours la taille d'un int!

Cela est dû à la promotion implicite de types via les conversions arithmétiques habituelles.

30
Lundin

Réponse rapide:

  • sizeof(a ? true : false) renvoie 4 parce que true et false sont définis dans <stdbool.h> comme 1 et 0, de sorte que l'expression se développe to sizeof(a ? 1 : 0) qui est une expression entière de type int, occupant 4 octets sur votre plate-forme. Pour la même raison, sizeof(true) aurait également pour résultat 4 sur votre système.

Notez cependant que:

  • sizeof(a ? a : a) est également évalué à 4 parce que l'opérateur ternaire effectue les promotions d'entier sur ses deuxième et troisième opérandes, s'il s'agit d'expressions entières. La même chose se produit bien sûr pour sizeof(a ? true : false) et sizeof(a ? (bool)true : (bool)false), mais l'expression entière comme bool se comporte comme prévu: sizeof((bool)(a ? true : false)) -> 1.

  • notez également que les opérateurs de comparaison évaluent les valeurs booléennes 1 ou 0, mais ont int type: sizeof(a == a) -> 4.

Les seuls opérateurs qui conservent la nature booléenne de a seraient:

  • l'opérateur de virgule: sizeof(a, a) et sizeof(true, a) sont évalués à 1 au moment de la compilation.

  • les opérateurs d'assignation: sizeof(a = a) et sizeof(a = true) ont pour valeur 1.

  • les opérateurs d'incrémentation: sizeof(a++) -> 1

Enfin, tout ce qui précède s’applique uniquement à C: C++ a une sémantique différente concernant le type bool, les valeurs booléennes true et false, les opérateurs de comparaison et l’opérateur ternaire: tous ces sizeof() expressions sont évaluées à 1 en C++.

21
chqrlie

Voici un extrait de quel est ce qui est inclus dans le source

#ifndef __cplusplus

#define bool    _Bool
#define true    1
#define false   0

#else /* __cplusplus */

Les macros true et false sont déclarées respectivement 1 et 0.

cependant, dans ce cas, le type est le type des constantes littérales. 0 et 1 sont des constantes entières qui entrent dans un int, leur type est donc int.

et la sizeof(int) dans votre cas est 4.

1
u__