Dlaczego " sizeof (a? true: false) " daje wyjście o 4 bajty?

Mam mały fragment kodu o operatorze sizeof z operatorem trójdzielnym:

#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;
}

Output (GCC):

1
1
4 // Why 4?

Ale tutaj,

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

Operator trójdzielny zwraca boolean type I sizeof bool type jest 1 bajtem w C.

To dlaczego sizeof(a ? true : false) daje wyjście o czterech bajtach?

Author: rsp, 2017-10-30

7 answers

To dlatego, że masz #include <stdbool.h>. Ten nagłówek definiuje makra true i false być 1 i 0, więc Twoje stwierdzenie wygląda tak:

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

sizeof(int) jest 4 na platformie.

 222
Author: Justin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-30 08:42:46

tutaj, operator trójdzielny return boolean type,

OK, to coś więcej!

W C, wynik to operacja trójwarstwowa jest typu int. [uwagi poniżej (1,2)]

Stąd wynik jest taki sam jak wyrażenie sizeof(int), na twojej platformie.


Uwaga 1: cytowanie C11, Rozdział §7.18, Boolean type and values <stdbool.h>

[....] Pozostałe trzy makra są odpowiednie do użycia w #if przetwarzaniu wstępnym dyrektywy. Oni are

true

Który rozszerza się do stałej całkowitej 1,

false

Który rozszerza się do stałej całkowitej 0, [....]

Uwaga 2: dla operatora warunkowego, rozdział §6.5.15, ( podkreślenie mine )

Pierwszy operand jest oceniany; pomiędzy jego oceną a ocena drugiego lub trzeciego operanda (w zależności od tego, która z tych wartości jest oceniana). Drugi operand na oceniany tylko wtedy, gdy pierwszy porównuje nierówność do 0; trzeci operand jest oceniany tylko wtedy, gdy pierwsze porównanie jest równe 0; wynikiem jest wartość drugiego lub trzeciego operandu (w zależności od tego, która z tych wartości jest oceniana), [...]

I

Jeśli zarówno drugi, jak i trzeci operand mają typ arytmetyczny, Typ wyniku, który byłby określone zwykłymi konwersjami arytmetycznymi, czy zostały one zastosowane do tych dwóch operandów, jest typem wyniku. [....]

Stąd wynik będzie typu integer, a ze względu na zakres wartości, stałe są dokładnie typu int.

To powiedziawszy, ogólna rada, int main() powinna być lepiej int main (void), aby być naprawdę zgodnym z normami.

 66
Author: Sourav Ghosh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-30 10:33:29

Operatorem trójdzielnym jest czerwony śledź.

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

Prints 4 (lub cokolwiek sizeof(int) jest na twojej platformie).

Poniższe założenie zakłada, że bool jest synonimem char lub podobnego typu O rozmiarze 1, A {[4] } jest większy od char.

Powodem, dla którego sizeof(true) != sizeof(bool) i sizeof(true) == sizeof(int) jest po prostu to, że true jest , a nie wyrażeniem typu bool. Jest to wyrażenie typu int. Jest #defined jak 1 w stdbool.h.

nie ma wartości R typu bool W C przy wszystkie. Każda taka wartość R jest natychmiast promowana do int, nawet jeśli jest używana jako argument do sizeof. Edit: ten akapit nie jest prawdziwy, argumenty do sizeof nie awansują do int. Nie wpływa to jednak na żadne z wniosków.

 58
Author: n.m.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-31 08:08:00

Jeśli chodzi o typ logiczny w C

Typ boolean został wprowadzony dość późno w języku C, W roku 1999. Wcześniej C nie miało typu boolean, ale zamiast tego używało int dla wszystkich wyrażeń boolean. Dlatego wszystkie operatory logiczne, takie jak > == ! etc zwracają int o wartości 1 lub 0.

Było zwyczajem, aby aplikacje używały domowych typów, takich jak typedef enum { FALSE, TRUE } BOOL;, co również sprowadza się do typów o rozmiarze int.

C++ miał dużo lepszy i jawny Typ boolean, bool, który nie był większy niż 1 bajt. Podczas gdy typy boolean lub wyrażenia w C skończyłyby się jako 4 bajty w najgorszym przypadku. W C++ wprowadzono pewną zgodność ze standardem C99. C otrzymuje Typ boolean _Bool oraz nagłówek stdbool.h.

stdbool.h zapewnia pewną kompatybilność z C++. Ten nagłówek definiuje makro bool (ta sama pisownia co słowo kluczowe C++), które rozszerza się do _Bool, typu, który jest małą liczbą całkowitą, prawdopodobnie o 1 bajt. Podobnie nagłówek zawiera dwa makra true i false, pisownia taka sama jak słowa kluczowe C++, , ale z kompatybilnością wsteczną do starszych programów C . Dlatego true i false rozszerzają się do 1 i 0 W C, a ich typem jest int. Te makra nie są w rzeczywistości typu boolean, jak odpowiednie słowa kluczowe C++.

Podobnie, dla celów zgodności wstecznej operatory logiczne w C nadal zwracają int do dnia dzisiejszego, nawet jeśli C obecnie ma Typ boolean. W C++ operatory logiczne zwracają bool. Tak więc wyrażenie takie jak sizeof(a == b) da rozmiar int W C, ale rozmiar bool W C++.

Odnośnie operatora warunkowego?:

Operator warunkowy ?: jest dziwnym operatorem z kilkoma dziwactwami. Powszechnym błędem jest przekonanie, że jest ona w 100% równoważna if() { } else {}. Niezupełnie.

Istnieje punkt sekwencji między oceną 1. A 2. lub 3. operand. Operator ?: ma gwarancję, że będzie oceniał tylko 2. lub 3. operand, więc nie będzie mógł wykonać żadnych efektów ubocznych tego operandu, który nie jest oceniany. Kod podobny do true? func1() : func2() nie wykona func2(). Jak na razie dobrze.

jednak, istnieje specjalna zasada mówiąca, że 2.i 3. operand muszą być domyślnie promowane i zrównoważone względem siebie za pomocą zwykłych konwersji arytmetycznych. (zasady promocji typu Implicit w C wyjaśnione tutaj ). Oznacza to, że 2. lub 3. operand będzie zawsze był co najmniej tak duży jak int.

Więc nie ma znaczenia, że true i false przypadkiem są typu int W C, ponieważ wyrażenie zawsze dawałoby co najmniej rozmiar int bez względu na to.

nawet jeśli przepisz wyrażenie do sizeof(a ? (bool)true : (bool)false) i tak zwróci rozmiar int !

Wynika to z niejawnej promocji typu poprzez zwykłe konwersje arytmetyczne.

 30
Author: Lundin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-01 06:29:38

Szybka odpowiedź:

  • sizeof(a ? true : false) oblicza się na 4 Ponieważ true i false są zdefiniowane w <stdbool.h> jako 1 i 0, więc wyrażenie rozszerza się do sizeof(a ? 1 : 0), które jest wyrażeniem całkowitym o typie int, które zajmuje 4 bajty na twojej platformie. Z tego samego powodu, sizeof(true) również oceniłby 4 w Twoim systemie.

Zauważ jednak, że:

  • sizeof(a ? a : a) również ewaluuje do 4, ponieważ operator trójdzielny wykonuje liczbę całkowitą na drugim i trzecim operandach, jeśli są to wyrażenia całkowite. To samo oczywiście dzieje się dla sizeof(a ? true : false) i sizeof(a ? (bool)true : (bool)false), ale odlewanie całego wyrażenia jako bool zachowuje się zgodnie z oczekiwaniami: sizeof((bool)(a ? true : false)) -> 1.

  • Należy również zauważyć, że operatory porównania oceniają wartości logiczne 1 lub 0, ale mają typ int: sizeof(a == a) -> 4.

Jedynymi operatorami, które zachowują boolowską naturę a będą:

  • Operator przecinka: zarówno sizeof(a, a), jak i sizeof(true, a) oceniają na 1 w czasie kompilacji.

  • Operatory przypisania: zarówno sizeof(a = a), jak i sizeof(a = true) mają wartość 1.

  • Operatory przyrostowe: sizeof(a++) -> 1

Wreszcie, wszystkie powyższe odnosi się tylko do C: C++ ma różne semantyki dotyczące typu bool, wartości logicznych true i false, operatorów porównawczych i operatora trójdzielnego: wszystkie te wyrażenia sizeof() oceniają się na 1 W C++.

 21
Author: chqrlie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-13 14:37:16

Oto fragment, z którego pochodzi to, co zawiera źródło

#ifndef __cplusplus

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

#else /* __cplusplus */

Tam makra true i false są zadeklarowane odpowiednio jako 1 i 0.

Jednak w tym przypadku typ jest typem stałych literalnych. Zarówno 0, jak i 1 są stałymi całkowitymi, które mieszczą się w int, więc ich typem jest int.

I sizeof(int) w Twoim przypadku jest 4.

 1
Author: u__,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-05 11:42:34

Nie ma boolean datatype w C, zamiast tego wyrażenia logiczne oceniają do wartości całkowitych 1 gdy true, w przeciwnym razie 0.

Wyrażenia warunkowe jak if, for, while, lub c ? a : b oczekuj liczby całkowitej, jeśli liczba jest niezerowa, jest ona rozważana true z wyjątkiem niektórych szczególnych przypadków, oto funkcja sumy rekurencyjnej, w której operator trójkowy będzie oceniał truen osiągnie 0.

int sum (int n) { return n ? n+sum(n-1) : n ;

Może być również używany do NULL sprawdzania wskaźnika, oto rekurencyjny funkcja, która wyświetla zawartość listy pojedynczo połączonej.

void print(sll * n){ printf("%d -> ",n->val); if(n->next)print(n->next); }
 -1
Author: Khaled.K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-03 12:31:01