Wiemy, że wszystkie liczby, które nie są równe, 0
są traktowane jak true
w C, więc możemy napisać:
int a = 16;
while (a--)
printf("%d\n", a); // prints numbers from 15 to 0
Jednak zastanawiałem się, czy prawda / fałsz są zdefiniowane jako 1
/ 0
w C, więc wypróbowałem poniższy kod:
printf("True = %d, False = %d\n", (0 == 0), (0 != 0)); // prints: True = 1, False = 0
Czy standard C wyraźnie wskazuje wartości prawdy prawda i fałsz odpowiednio jako 1
i 0
?
gcc
ze-std=c89
i to daje taki sam wynik.Odpowiedzi:
Standard C definiuje
true
ifalse
jako makra, wstdbool.h
których rozszerzają się odpowiednio do1
i0
.C11-§7.18:
Dla operatorów
==
i!=
, mówi normaC11-§6.5.9 / 3:
źródło
0 == 0
i0 != 0
itp., A nie wartości makr.true
miał na myśli „wartość prawdziwego porównania” czy coś takiego, a nie makrotrue
ctrl
+f
;)NaN == NaN
jest fałszywe iNaN != NaN
prawdziwe. Nie ma problemu z tym stwierdzeniem.Nie jest to wyraźnie wskazane w C11. Wszystkie operacje na poziomie języka zwrócą wartość 1 jako prawdziwą (i zaakceptują wszystkie wartości niezerowe, w tym NaN, jako prawdziwe).
_Bool
martwisz się, to prawda musi wynosić 1, ponieważ standard wymaga, aby zawierała tylko 0 i 1. (§6.2.5 / 2).<stdbool.h>
makrotrue
rozszerza się do1
(§7.18 / 3)==
,!=
,<
,>
,<=
I>=
powrót 0 lub 1 (w §6.5.8 / 6, §6.5.9 / 3).!
,&&
I||
powrót 0 lub 1 (§6.5.3.3 / 5 §6.5.13 / 3, §6.5.14 / 3)defined
rozwija się do 0 lub 1 (§6.10.1 / 1)Ale wszystkie standardowe funkcje biblioteczne, np. Po
islower
prostu mówią „niezerowe” dla prawdziwości (np. §7.4.1 / 1, §7.17.5.1 / 3, §7.30.2.1 / 1, §7.30.2.2.1 / 4).źródło
Istnieją dwa obszary standardu, o których należy pamiętać, mając do czynienia z wartościami boolowskimi (przez które mam na myśli wartości prawda / fałsz, a nie określony
bool/_Bool
typ C ) w C.Pierwszy dotyczy wyniku wyrażeń i można go znaleźć w różnych częściach
C11 6.5 Expressions
(na przykład operatory relacyjne i operatory równości). Najważniejsze jest to, że za każdym razem, gdy wartość logiczna jest generowana przez wyrażenie, to ...Zatem tak, wynikiem każdego wyrażenia generującego wartości logiczne będzie jeden dla prawdy lub zero dla fałszu. Dopasowuje Co będzie można znaleźć w
stdbool.h
których poziom makrtrue
ifalse
są zdefiniowane w ten sam sposób.Należy jednak pamiętać, że zgodnie z zasadą solidności „bądź konserwatywny w tym, co wysyłasz, a liberalny w tym, co akceptujesz”, interpretacja liczb całkowitych w kontekście boolowskim jest nieco bardziej swobodna.
Ponownie, z różnych części
6.5
zobaczysz język taki jak:Z tego (i innych części) wynika, że zero jest uważane za fałszywe, a każda inna wartość jest prawdziwa.
Nawiasem mówiąc, język określający, jaka wartość jest używana do generowania i interpretacji wartości logicznych, pojawia się również w C99 i C89, więc są one dostępne już od dłuższego czasu. Nawet K&R (drugie wydanie ANSI-C i pierwsze wydanie) określiło to w przypadku segmentów tekstu, takich jak:
Makra w programie
stdbool.h
pojawiają się również w C99, ale nie w C89 ani K&R, ponieważ ten plik nagłówkowy nie istniał w tym momencie.źródło
||
,==
,!=
itp wydajnośćint
, a nie typu booleanif
,while
,for
, itp,«prawda»oznacza po prostu«non-zero».” To najistotniejsza część odpowiedzi i moim zdaniem jest to niefortunny wybór Dennisa Ritchiego z dawnych czasów. Każdy, kto napisał funkcje, które zwracają kody błędów jako wartość zwracaną, zwykle ma,#define noErr 0
a każdy niezerowy kod błędu jest błędem. A potem problemem jest prostota i pięknoif ( ready_to_do_something() ){do_something();}
nie działa. Musi brzmieć:if ( !not_ready_to_do_something() ){do_something();}
„Jest wiele kłamstw, ale tylko jedna prawda”. PRAWDA powinno być 0.A.7.6/7/10/11
(relacyjne / równość / logiczne i / logiczne lub) wszystkie określają, że daje wynik 0 lub 1. Zaktualizuj odpowiedź, aby to uwzględnić.Mylisz wiele różnych rzeczy: instrukcje sterujące, operatory i typy boolowskie. Każdy ma swoje własne zasady.
Instrukcje kontrolne działają jak na przykład
if
instrukcja C11 6.4.8.1:while
,for
Etc mają taką samą regułę. Nie ma to nic wspólnego z „prawdą” lub „fałszem”.Jeśli chodzi o operatory, które rzekomo dają wynik boolowski, w rzeczywistości dają one wynik
int
o wartości 1 lub 0. Na przykład operatory równości, C11 6.5.9:Wszystko to wynika z tego, że C nie miał typu boolowskiego aż do roku 1999, a nawet kiedy go otrzymał, powyższe zasady nie zostały zmienione. Tak więc w przeciwieństwie do większości innych języków programowania, w których instrukcje i operatory dają typ boolowski (jak C ++ i Java), po prostu dają
int
znak o wartości zero lub niezerowej. Na przykładsizeof(1==1)
da 4 w C, ale 1 w C ++.Rzeczywisty typ boolowski w C jest nazwany
_Bool
i wymaga nowoczesnego kompilatora. Nagłówekstdbool.h
makra Definiujebool
,true
orazfalse
, że rozszerzają się_Bool
,1
a0
odpowiednio (dla kompatybilności z C ++).Uważa się jednak, że dobrą praktyką programowania jest traktowanie instrukcji sterujących i operatorów tak, jakby faktycznie wymagały / dawały typ boolowski. Niektóre standardy kodowania, takie jak MISRA-C, zalecają taką praktykę. To jest:
if(ptr == NULL)
zamiastif(ptr)
.if((data & mask) != 0)
zamiastif(data & mask)
.Celem takiego stylu jest zwiększenie bezpieczeństwa typów za pomocą narzędzi do analizy statycznej, co z kolei zmniejsza liczbę błędów. Prawdopodobnie ten styl ma znaczenie tylko wtedy, gdy używasz analizatorów statycznych. Chociaż w niektórych przypadkach prowadzi to na przykład do bardziej czytelnego, samodokumentującego się kodu
if(c == '\0')
Dobrze, zamiar jest jasny, kod samodokumentuje się.
przeciw
if(c)
Zły. Może oznaczać wszystko i musimy poszukać typu,
c
aby zrozumieć kod. Czy jest to liczba całkowita, wskaźnik czy znak?źródło
sizeof(bool)
jest specyficzna dla implementacji w C ++. Zobacz stackoverflow.com/questions/4897844/is-sizeofbool-defined .if(ptr != NULL)
, czy możeif(!ptr)
?if(c == '\0')
nadaje się do szczególnie powszechnego błędu programowania przez początkującychif(c = '\0')
, więc go unikam. Zgoda,if(c)
jest źle ... powinno być na przykładif(valveIsOpen)
Programowałem w wielu językach. Widziałem, że prawda wynosi 1 lub -1 w zależności od języka. Logika stojąca za prawdziwym byciem 1 polegała na tym, że bit miał wartość 0 lub 1. Logika prawdziwego bycia -1 była taka, że! operator był dopełnieniem. Zmienił wszystkie jedynki na 0 i wszystkie 0 na 1 w int. Tak więc dla int,! 0 = -1 i! (- 1) = 0. To mnie zaskoczyło na tyle, że nie porównuję czegoś, aby było == prawda, ale zamiast tego porównuję to, aby było! = Fałsz. W ten sposób mój styl programowania działa w każdym języku. Więc moja odpowiedź brzmi: nie martw się o to, ale programuj tak, aby Twój kod działał poprawnie.
źródło
Tej odpowiedzi należy przyjrzeć się bliżej.
Rzeczywista definicja w C ++ jest taka, że wszystko inne niż 0 jest traktowane jako prawdziwe. Dlaczego jest to istotne? Ponieważ C ++ nie wie, czym jest liczba całkowita, na podstawie tego, jak o niej myślimy - tworzymy to znaczenie, wszystko, co zawiera, to powłoka i reguły dotyczące tego, co to znaczy. Wie jednak, czym są bity, które składają się na liczbę całkowitą.
1 jako liczba całkowita jest luźno reprezentowana w bitach, powiedzmy 8-bitowa wartość int ze znakiem jako 0000 0001. Wiele razy to, co widzimy wizualnie, jest trochę kłamstwem, -1 jest znacznie bardziej powszechnym sposobem przedstawienia tego ze względu na charakter ze znakiem „integer”. Naprawdę nie mogę mieć na myśli prawdziwej, właściwej, dlaczego? Ponieważ NIE jest to operacja 1111 1110. To naprawdę poważny problem dla boolean. Kiedy mówimy o wartości logicznej, jest to tylko 1 bit - to naprawdę proste, 0 to fałsz, a 1 to prawda. Wszystkie operacje logiczne są banalne. Dlatego „-1” powinno być oznaczone jako „prawda” dla liczb całkowitych (ze znakiem). 1111 1111 NOT'ed staje się 0000 0000 - logika się utrzymuje i jesteśmy w porządku. Niepodpisane liczby int są nieco skomplikowane i w przeszłości były znacznie częściej używane - gdzie 1 oznacza prawdę, ponieważ łatwo jest zasugerować logikę, że ”
To jest wyjaśnienie. Mówię, że przyjęta odpowiedź jest zła - w definicji C / C ++ nie ma jasnej definicji. Wartość logiczna jest wartością logiczną, możesz traktować liczbę całkowitą jako wartość logiczną, ale fakt, że wynik jest liczbą całkowitą, nie mówi nic o faktycznie wykonywanej operacji.
źródło
Stało się tak z powodu operatorów relacyjnych w twoim
printf
oświadczeniu.Operator
==
i operator!=
Ponieważ
(0 == 0)
tak jest, daje wartość1
podczas gdy
(0 != 0)
nie jest prawdą, daje wartość0
.źródło