Mam mały fragment kodu o sizeof
operatorze z operatorem trójskładnikowym:
#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;
}
Wyjście ( GCC ):
1
1
4 // Why 4?
Ale tu,
printf("%zu\n", sizeof(a ? true : false)); // Why 4?
operator trójargumentowy zwraca boolean
typ, a rozmiar bool
typu to 1
bajt w C.
Wtedy dlaczego sizeof(a ? true : false)
dać moc czterech bajtów?
sizeof(true)
asizeof(false)
także 4: ide.geeksforgeeks.org/O5jvuN_Bool
rozmiar 1, ale nietrue
ifalse
. Ale standard nie ma nic do powiedzenia na ten temat, o ile wiem.char a;
sizeof(a) == 1
isizeof('a') == sizeof(int)
(w C). Nie chodzi o implementację, chodzi o język.sizeof(true)
? być może sprawi, że rozrzedzenie będzie trochę bardziej wyraźne (w szczególności stanie się oczywiste, że operatorem trójskładnikowym jest czerwony śledź).true
jest równe#define
1,stdbool.h
więc tak, to jest dosłowna definicja.Odpowiedzi:
To dlatego, że masz
#include <stdbool.h>
. Ten nagłówek definiuje makratrue
ifalse
być1
i0
, więc twoje oświadczenie wygląda następująco:sizeof(int)
to 4 na twojej platformie.źródło
sizeof(a ? (uint8_t)1 : (uint8_t)0);
dałoby również wynik 4. Promocja liczb całkowitych?:
operandów jest tutaj ważną częścią, a nie rozmiartrue
ifalse
.int
bez promocji. Powodem, dla którego nie można tego „naprawić”, są domyślne promocje.true
i niefalse
są makrami; są to słowa kluczowe. Nie są zdefiniowane jako i , ale jako prawdziwe i fałszywe wartości typu.1
0
bool
sizeof(true)
to 1. demo .OK, to nie wszystko!
W C wynik tej trójskładnikowej operacji 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>
Uwaga 2: Dla operatora warunkowego, rozdział §6.5.15, ( moje wyróżnienie )
i
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ć lepsza,int main (void)
aby być naprawdę zgodnym ze standardami.źródło
<stdbool.h>
definiuje MAKRA jako typuint
.. czy to źle?Operator trójskładnikowy to śledź czerwony.
drukuje 4 (lub cokolwiek
sizeof(int)
jest na twojej platformie).Poniższy tekst zakłada, że
bool
jest to synonimchar
rozmiaru 1 lub podobnego typu iint
jest większy niżchar
.Powodem,
sizeof(true) != sizeof(bool)
isizeof(true) == sizeof(int)
to tylko dlatego, żetrue
to nie jest wyrazem typubool
. To wyraz typuint
. Jest#define
jak1
wstdbool.h
.W ogóle nie ma wartości typu rEdycja: ten akapit nie jest prawdziwy, argumenty, dobool
. Każda taka wartość r jest natychmiast promowana doint
, nawet jeśli jest używana jako argument dosizeof
.sizeof
których nie można awansowaćint
. Nie wpływa to jednak na żadne z wniosków.źródło
(bool)1
jest wartością typu rbool
?printf("%u\n", sizeof((char) 1));
drukuje1
na mojej platformie, podczas gdyprintf("%u\n", sizeof(1));
drukuje4
. Czy to nie znaczy, że twoje stwierdzenie „Każda taka wartość r jest natychmiast promowana do int, nawet gdy jest używana jako argument do sizeof” jest fałszywa?true
etc nie ma tak naprawdę znaczenia w przypadku,?:
ponieważ i tak jest promowany jako liczba całkowitaint
. Oznacza to, że odpowiedź powinna wskazywać, dlaczego?:
jest czerwony śledź.Odnośnie typu boolowskiego w C
Typ boolowski został wprowadzony dość późno w języku C, w roku 1999. Wcześniej C nie posiadał typu boolowskiego, ale zamiast tego był używany
int
we wszystkich wyrażeniach boolowskich. Dlatego wszystkie operatory logiczne, takie jak> == !
etc zwracająint
wartość1
lub0
.Niestandardowe było, aby aplikacje korzystały z typów domowych, takich jak
typedef enum { FALSE, TRUE } BOOL;
, co również sprowadza się doint
typów o dużych rozmiarach.C ++ miał znacznie lepszy i jawny typ boolowski
bool
, który nie był większy niż 1 bajt. Podczas gdy typy boolowskie lub wyrażenia w C w najgorszym przypadku miałyby 4 bajty. Pewien sposób na kompatybilność z C ++ został wprowadzony w C ze standardem C99. C otrzymał wtedy typ boolowski,_Bool
a także nagłówekstdbool.h
.stdbool.h
zapewnia pewną zgodność z C ++. Ten nagłówek definiuje makrobool
(taka sama pisownia jak słowo kluczowe w C ++), które rozwija się do_Bool
, typ, który jest typem małej liczby całkowitej, prawdopodobnie o rozmiarze 1 bajtu. Podobnie, nagłówek zawiera dwa makratrue
ifalse
, tak samo jak C ++ pisowni słów kluczowych, ale z wstecznej kompatybilności dla starszych programów C . Dlategotrue
ifalse
rozwinąć do1
iw0
C, a ich typ toint
. Te makra nie są w rzeczywistości typu boolowskiego, jak odpowiadałyby im słowa kluczowe C ++.Podobnie, dla celów zgodności z poprzednimi wersjami, operatory logiczne w C nadal zwracają an
int
do dnia dzisiejszego, mimo że C obecnie ma typ boolowski. W C ++ operatory logiczne zwracają plikbool
. Zatem wyrażenie takie jaksizeof(a == b)
da rozmiar literyint
w C, ale rozmiar abool
w C ++.Odnośnie operatora warunkowego
?:
Operator warunkowy
?:
jest dziwnym operatorem z kilkoma dziwactwami. Powszechnym błędem jest przekonanie, że jest to równoważne w 100%if() { } else {}
. Nie do końca.Istnieje punkt sekwencji między obliczeniem pierwszego i drugiego lub trzeciego operandu.
?:
Operator gwarantuje jedynie oceniać albo 2 lub 3rd argumentu, więc nie może wykonywać żadnych skutków ubocznych argumentu, który nie jest uwzględniany. Kod taki jaktrue? func1() : func2()
nie będzie wykonywanyfunc2()
. Na razie w porządku.Istnieje jednak specjalna reguła mówiąca, że drugi i trzeci operand muszą być niejawnie promowane i równoważone względem siebie za pomocą zwykłych konwersji arytmetycznych . ( Wyjaśniono tutaj niejawne reguły promocji typu w języku C ). Oznacza to, że drugi lub trzeci operand zawsze będzie co najmniej tak duży jak plik
int
.Więc to nie ma znaczenia
true
ifalse
tak się składa, że jest to typint
w C, ponieważ wyrażenie zawsze podawałoby co najmniej rozmiarint
nieważne.Nawet gdybyś przepisał wyrażenie na to, nadal zwróciłoby to rozmiar !
sizeof(a ? (bool)true : (bool)false)
int
Dzieje się tak z powodu niejawnej promocji typu poprzez zwykłe konwersje arytmetyczne.
źródło
sizeof(bool)==1
.Szybka odpowiedź:
sizeof(a ? true : false)
szacuje się na4
ponieważtrue
ifalse
są zdefiniowane odpowiednio w<stdbool.h>
as1
i0
, więc wyrażenie rozwija się do wyrażeniasizeof(a ? 1 : 0)
będącego liczbą całkowitą o typieint
, zajmującego 4 bajty na Twojej platformie. Z tego samego powodusizeof(true)
powinien również ocenić4
w twoim systemie.Należy jednak pamiętać, że:
sizeof(a ? a : a)
4
oblicza się również do, ponieważ operator trójskładnikowy wykonuje promocje liczb całkowitych na swoim drugim i trzecim operandzie, jeśli są to wyrażenia całkowite. To samo dzieje się w trakciesizeof(a ? true : false)
, asizeof(a ? (bool)true : (bool)false)
, a odlanie całego ekspresji jakbool
zachowuje się, jak oczekiwanosizeof((bool)(a ? true : false)) -> 1
.również pamiętać, że operatory porównania oceny do wartości logicznych
1
lub0
, ale mająint
typ:sizeof(a == a) -> 4
.Jedynymi operatorami, które zachowują logiczną naturę,
a
byłyby:operator przecinka: oba
sizeof(a, a)
isizeof(true, a)
obliczane do1
w czasie kompilacji.operatory przypisania: both
sizeof(a = a)
isizeof(a = true)
mają wartość1
.operatory przyrostu:
sizeof(a++) -> 1
Wreszcie, wszystkie powyższe dotyczą tylko C: C ++ ma inną semantykę dotyczącą
bool
typu, wartości logicznychtrue
ifalse
operatorów porównania oraz operatora trójskładnikowego: wszystkie tesizeof()
wyrażenia są obliczane1
w C ++.źródło
true
ifalse
są, ponieważ?:
operandy i tak byłyby promowane do liczby całkowitejint
. Wsizeof(a ? (uint8_t)true : (uint8_t)false)
rezultacie również da wynik 4.int
Oto fragment, z którego pochodzi zawartość
Tam makra
true
ifalse
są zadeklarowane odpowiednio jako 1 i 0.jednak w tym przypadku typ jest typem stałych literału. Zarówno 0, jak i 1 to stałe całkowite, które mieszczą się w int, więc ich typ to int.
aw
sizeof(int)
twoim przypadku to 4.źródło
W języku C nie ma logicznego typu danych, zamiast tego wyrażenia logiczne są obliczane na wartości całkowite,
1
jeśli prawda, w przeciwnym razie0
.Wyrażenia warunkowe podoba
if
,for
,while
, lubc ? a : b
oczekiwać liczbę całkowitą, jeśli liczba jest różna od zera to uważanetrue
za wyjątkiem pewnych szczególnych przypadkach, oto funkcji rekurencyjnej suma w którym trójargumentowy-operator ocenitrue
ażn
zasięgiem0
.Może być również użyty do
NULL
sprawdzenia wskaźnika, oto funkcja rekurencyjna, która wypisuje zawartość listy połączonej pojedynczo.źródło