Lo standard C indica esplicitamente il valore di verità come 0 o 1?


86

Sappiamo che tutti i numeri che non sono uguali a 0sono visti come truein C, quindi possiamo scrivere:

Tuttavia, mi chiedevo se true / false sono definite come 1/ 0in C, quindi ho provato il codice seguente:

Lo standard C indica esplicitamente i valori di verità di vero e falso come 1e 0rispettivamente?


3
Immagino che questa domanda SO sia rilevante
Imran Ali

3
Provo a eseguire questo gcccon -std=c89e produce lo stesso risultato.
Kevin Dong

1
@Blackhole, dalle 15 alle 0.
Arturo Torres Sánchez

6
Quasi ingannato, ma più di un decennio prima di SO / SE: c-faq.com/bool/bool2.html .
dave_thompson_085

1
Quel falso è zero è canone, tuttavia vero è generalmente considerato "non zero". Tuttavia, essendo i programmatori quello che sono, abbiamo tutti usato 1 come "non zero" per i nostri vari motivi. Sei incoraggiato a non fidarti che un vero sia esattamente 1. Mentre (0 == 0) è uno nel tuo esempio, qualcosa come (12 == 12) potrebbe facilmente avere il valore 12; anche "vero".
Ingegnere

Risposte:


96

Lo standard C indica esplicitamente i valori di verità di truee falsecome 0e 1rispettivamente?

Lo standard C definisce trueefalse come macro in stdbool.hcui si espandono rispettivamente a 1e 0.

C11-§7.18:

Le restanti tre macro sono adatte per l'uso nelle #ifdirettive di pre-elaborazione. Loro sono

che si espande alla costante intera 1,

che si espande alla costante intera 0[...]

Per gli operatori ==e !=, dice lo standard

C11-§6.5.9 / 3:

Gli operatori ==(uguale a) e !=(non uguale a) sono analoghi agli operatori relazionali tranne per la loro precedenza inferiore. 108) Ciascuno degli operatori restituisce 1se la relazione specificata è vera e 0se è falsa. Il risultato è tipo int. Per ogni coppia di operandi, è vera esattamente una delle relazioni.


20
Mi sembra che la domanda riguardi 0 == 0e così 0 != 0via, non il valore delle macro.
MM

9
Penso che quando ha scritto trueintendesse "il valore di un vero confronto" o qualcosa del genere, non la macrotrue
MM

1
@KevinDong; Sì, la bozza C99 ha un paragrafo simile.
haccks

1
@haccks: puoi dirlo senza esitazione "identico" Ho appena scritto la tua citazione perché ero troppo pigro per cercare per paragrafo dato che mi riferisco a c99 quando mai necessario. E sono stato in grado di trovare da solo la ricerca tramite ctrl+ f;)
Dhein

2
@ MoooingDuck: NaN == NaNè falso ed NaN != NaNè vero. Non ci sono problemi con questa affermazione.
kennytm

51

Non è esplicitamente indicato in C11. Tutte le operazioni a livello di lingua restituiranno 1 come true (e accetteranno come true qualsiasi valore diverso da zero incluso NaN).

  • Se ti preoccupi _Bool, allora vero deve essere 1 perché lo standard richiede solo che contenga 0 e 1. (§6.2.5 / 2).
  • Anche nella <stdbool.h>macro si trueespande in 1(§7.18 / 3)
  • ==, !=, <, >, <=E >=restituire 0 o 1 (§6.5.8 / 6, §6.5.9 / 3).
  • !, &&E ||restituire 0 o 1 (§6.5.3.3 / 5, §6.5.13 / 3, §6.5.14 / 3)
  • defined si espande a 0 o 1 (§6.10.1 / 1)

Ma tutte le funzioni di libreria standard, ad esempio, islowerdicono semplicemente "diverso da zero" per la verità (ad esempio §7.4.1 / 1, §7.17.5.1 / 3, §7.30.2.1 / 1, §7.30.2.2.1 / 4).


§6.2.5 / 2 : un oggetto dichiarato come tipo _Boolè abbastanza grande da memorizzare i valori 0 e 1.

§6.5.5.3 / 5 : Il risultato dell'operatore di negazione logica !è 0 se il valore del suo operando è diverso da 0, 1 se il valore del suo operando è uguale a 0. ...

§6.5.8 / 6 : Ciascuno degli operatori <(minore di), >(maggiore di), <=(minore o uguale a) e >=(maggiore o uguale a) restituirà 1 se la relazione specificata è vera e 0 se è falso. 107) ...

§6.5.9 / 3 : ==(uguale a) e!= operatori (non uguale a) sono analoghi agli operatori relazionali tranne che per la loro precedenza inferiore.108) Ciascuno degli operatori restituisce 1 se la relazione specificata è vera e 0 se è falso. ...

§6.5.13 / 3 : l' &&operatore restituisce 1 se entrambi i suoi operandi sono diversi da 0; ...

§6.5.14 / 3 : l' ||operatore restituisce 1 se uno dei suoi operandi è diverso da 0; ...

§6.10.1 / 1 : ... può contenere espressioni di operatori unari della forma - defined identifier- o - defined ( identifier )- che restituiscono 1 se ...

§7.4.1 (Funzioni di classificazione dei caratteri) / 1 : Le funzioni in questo sottoclausola restituiscono diverso da zero (vero) se e solo se ...

§7.18 / 3 : Le restanti tre macro sono adatte per l'uso nelle #ifdirettive di pre-elaborazione. Sono - true- che si espande alla costante intera 1, ...

§7.17.5.1 / 3 : La atomic_is_lock_freefunzione generica restituisce diverso da zero (vero) se e solo se le operazioni dell'oggetto sono libere da blocchi. ...

§7.30.2.1 (Funzioni di classificazione dei caratteri estesi) / 1 : Le funzioni in questo sottopunto restituiscono diverso da zero (vero) se e solo se ...

§7.30.2.2.1 / 4 : La iswctypefunzione restituisce diverso da zero (vero) se e solo se ...


23

Ci sono due aree dello standard di cui devi essere consapevole quando hai a che fare con valori booleani (con cui intendo valori vero / falso piuttosto che lo specifico C bool/_Bool tipo ) in C.

Il primo ha a che fare con il risultato di espressioni e può essere trovato in varie parti di C11 6.5 Expressions(operatori relazionali e di uguaglianza, ad esempio). La conclusione è che, ogni volta che un valore booleano viene generato da un'espressione, esso ...

... restituisce 1 se la relazione specificata è vera e 0 se è falsa. Il risultato è di tipo int.

Quindi, sì, il risultato di qualsiasi espressione che genera booleani sarà uno per vero o zero per falso. Questo corrisponde a ciò che troverai in stdbool.hcui le macro standard trueefalse sono definite allo stesso modo.

Tieni presente tuttavia che, seguendo il principio di robustezza di "sii conservatore in ciò che mandi, liberale in ciò che accetti", l'interpretazione dei numeri interi nel contesto booleano è un po 'più rilassata.

Ancora una volta, da varie parti di 6.5, vedrai un linguaggio come:

L' ||operatore restituisce 1 se uno dei suoi operandi è diverso da 0; in caso contrario, restituisce 0. Il risultato è di tipo int.

Da questo (e da altre parti), è ovvio che zero è considerato falso e qualsiasi altro valore è vero.


Per inciso, il linguaggio che specifica il valore utilizzato per la generazione e l'interpretazione booleana appare anche in C99 e C89, quindi sono in circolazione da un po 'di tempo. Anche K&R (ANSI-C seconda edizione e prima edizione) lo ha specificato, con segmenti di testo come:

Espressioni relazionali like i > jed espressioni logiche collegate da &&e ||sono definite per avere valore 1se true, e0 se falso.

Nella parte di prova if, while,for , ecc, "vero" significa semplicemente "non-zero".

Il && operatore ... restituisce 1 se entrambi i suoi operandi sono diversi da zero, 0 altrimenti.

L' ||operatore ... restituisce 1 se uno dei suoi operandi è diverso da zero e 0 altrimenti.

Le macro in stdbool.happaiono anche in C99, ma non in C89 o K&R poiché quel file di intestazione non esisteva a quel punto.


2
notare che ||, ==, !=ecc rendimento int, non un tipo booleano
MM

2
Voto questa domanda per quella corretta. Per me la domanda riguarda anche gli operatori relazionali e non le macro.
ckruczek

"Nella parte di prova di if, while, for, ecc, 'vero' significa semplicemente 'non-zero'." Questa è la parte saliente della risposta ed è, a mio parere, una scelta sfortunata di Dennis Ritchie di molto tempo fa. Chiunque abbia scritto funzioni che restituiscono codici di errore come il valore restituito generalmente ha #define noErr 0e qualsiasi codice di errore diverso da zero è un errore. E poi il problema è la semplicità e la bellezza di if ( ready_to_do_something() ){do_something();} non funziona. Deve essere if ( !not_ready_to_do_something() ){do_something();}"Ci sono molte falsità, ma solo una verità". TRUE dovrebbe essere 0.
robert bristow-johnson

Per curiosità, in che modo le prime bozze di regole C hanno specificato il comportamento di "&&" e "||" nel caso in cui gli operandi avessero valori diversi da 0 o 1? Il testo che citi dice "espressioni logiche" collegate da && e ||, ma cosa succede se quegli operatori collegano cose diverse dalle espressioni logiche?
supercat

1
@sdenham, sì. Nella prima copia di K&R che ho (prima edizione, tiratura 14, una così presto che menziona le caratteristiche hardware di quattro macchine tipiche, il PDP-11, Honeywell-6000, IBM-370 e Interdata-8/32), A.7.6/7/10/11(relazionale / uguaglianza / logico-e / logico-o) tutti specificano che restituisce 0 o 1 come risultato. Avere una risposta aggiornata per includerla.
paxdiablo

10

Stai mescolando molte cose diverse: istruzioni di controllo, operatori e tipi booleani. Ognuno ha le proprie regole.

Le istruzioni di controllo funzionano come, ad esempio, l' ifistruzione C11 6.4.8.1:

In entrambe le forme, la prima sottostrazione viene eseguita se l'espressione è diversa da 0.

while, for così via hanno la stessa regola. Questo non ha nulla a che fare con "vero" o "falso".

Per quanto riguarda gli operatori che presumibilmente producono un risultato booleano, in realtà stanno restituendo un intcon valore 1 o 0. Ad esempio gli operatori di uguaglianza, C11 6.5.9:

Ciascuno degli operatori restituisce 1 se la relazione specificata è vera e 0 se è falsa

Tutto quanto sopra è perché C non aveva un tipo booleano fino all'anno 1999, e anche quando ne ha ottenuto uno, le regole precedenti non sono state modificate. Quindi, a differenza della maggior parte degli altri linguaggi di programmazione in cui le istruzioni e gli operatori producono un tipo booleano (come C ++ e Java), producono solo un int, con un valore zero o non zero. Per esempio,sizeof(1==1) darà 4 in C ma 1 in C ++.

Il tipo booleano effettivo in C è denominato _Boole richiede un compilatore moderno. L'intestazione stdbool.hdefinisce macro bool, truee false, che si espandono per _Bool, 1e 0rispettivamente (per la compatibilità con C ++).


Tuttavia, è considerata buona pratica di programmazione trattare le istruzioni di controllo e gli operatori come se effettivamente richiedessero / producessero un tipo booleano. Alcuni standard di codifica come MISRA-C consigliano tale pratica. Questo è:

if(ptr == NULL)invece di if(ptr).

if((data & mask) != 0) invece di if(data & mask) .

Lo scopo di tale stile è aumentare la sicurezza dei tipi con l'aiuto di strumenti di analisi statica, che a loro volta riducono i bug. Probabilmente, questo stile è significativo solo se si utilizzano analizzatori statici. Anche se in alcuni casi porta a un codice più leggibile e auto-documentante, per esempio

Bene, l'intento è chiaro, il codice si auto-documenta.

contro

Male. Potrebbe significare qualsiasi cosa, e dobbiamo cercare il tipo di cper capire il codice. È un numero intero, un puntatore o un carattere?


1
sizeof(bool)è specifica dell'implementazione in C ++. Vedi stackoverflow.com/questions/4897844/is-sizeofbool-defined .
David Hammen

@DavidHammen Proprio come sizeof (0 == 0) è definito anche dall'implementazione. È solo un esempio.
Lundin

Pensavo che il C avesse cambiato le regole per i tipi booleani. Altri tipi di tipi uintN (inclusi i tipi "bit" di molti compilatori più vecchi) memorizzano gli N bit inferiori di un valore e ignorano qualsiasi bit superiore, mentre i nuovi tipi booleani effettivamente "o" insieme tutti i bit.
supercat

1
Dovrebbe essere if(ptr != NULL), o forse if(!ptr)?
Mathieu K.

1
if(c == '\0')si presta all'errore di codifica particolarmente comune dei principianti if(c = '\0'), quindi lo evito. D'accordo, if(c)è un male ... dovrebbe essere, per esempio,if(valveIsOpen)
aja

4

Ho programmato in molte lingue. Ho visto true essere 1 o -1 a seconda della lingua. La logica dietro il vero essere 1 era che un po 'era 0 o 1. La logica dietro il vero essere -1 era che il! operatore era un proprio complemento. Ha cambiato tutti gli 1 in 0 e tutti gli 0 in 1 in un int. Quindi, per un int,! 0 = -1 e! (- 1) = 0. Questo mi ha fatto scattare abbastanza da non confrontare qualcosa per essere == true, ma invece per essere! = False. In questo modo, il mio stile di programmazione funziona in ogni lingua. Quindi la mia risposta è non preoccuparti, ma programma in modo che il tuo codice funzioni correttamente in entrambi i casi.


come si può! cambia tutti gli 0 in 1 e produci ancora 0 per! 5?
codeshot

@codeshot Non può. Ma il punto che sta dicendo è che non tutte le lingue trattano l'operando di! come booleano. Qualche sorpresa! come ~ di C, cioè un complemento bit per bit. In tal caso, determinare il valore risultante richiede innanzitutto di conoscere il tipo di variabile, quindi! (Uint32_t) 5 sarebbe 4.294.967.290. Ma! 0 è ancora 4.294.967.295 e 4.294.967.295 è vero.
Pegasus Epsilon

1

Questa risposta deve essere esaminata un po 'più da vicino.

La definizione effettiva in C ++ è che tutto ciò che non è 0 viene considerato vero. Perché è rilevante? Poiché il C ++ non sa cosa sia un numero intero da come lo pensiamo: creiamo quel significato, tutto ciò che contiene è la shell e le regole per ciò che significa. Ma sa cosa sono i bit, ciò che compone un numero intero.

1 come numero intero è liberamente rappresentato in bit, ad esempio un int con segno a 8 bit come 0000 0001. Molte volte ciò che vediamo visivamente è un po 'una bugia, -1 è un modo molto più comune di rappresentarlo a causa della natura del segno di "intero". Non posso davvero significare vero corretto, perché? Perché NON l'operazione è 1111 1110. Questo è un grosso problema per un booleano. Quando parliamo di un booleano, è solo 1 bit: è davvero semplice, 0 è falso e 1 è vero. Tutte le operazioni logiche sono banali. Questo è il motivo per cui "-1" dovrebbe essere designato come "vero" per i numeri interi (con segno). 1111 1111 NOT'ed diventa 0000 0000 --- la logica tiene e siamo a posto. Gli int senza segno sono un po 'complicati ed erano molto più comunemente usati in passato, dove 1 significa vero perché è facile implicare la logica che "

Questa è la spiegazione. Dico che la risposta accettata qui è sbagliata: non esiste una definizione chiara nella definizione C / C ++. Un booleano è un booleano, puoi trattare un numero intero come un booleano, ma il fatto che l'output sia un numero intero non dice nulla sull'operazione che viene effettivamente eseguita è bit per bit.


4
La domanda riguardava C, non C ++.
glglgl

0

È successo a causa degli operatori relazionali nel tuo printf dichiarazione.

Operatore == e operatore!=

Poiché (0 == 0)è vero, dà un valore1

mentre, (0 != 0)non è vero, dà un valore 0.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.