Strane definizioni di macro TRUE e FALSE


300

Ho visto le seguenti macro definizioni in un libro di programmazione.

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

Non c'era spiegazione lì.

Per favore, spiegami come funzioneranno come TRUEe FALSE.


63
Penso che sia solo un modo divertente per definire VERO come 1 e FALSO come 0
BlackDwarf

160
Nota che questa è una terribile idea senza parentesi attorno a quelle espressioni. Voglio dire, è un'idea terribile con loro, ma senza che tu stia solo chiedendo una lunga notte di debug.
TartanLlama,

70
Posso sapere il libro di programmazione a cui stai facendo riferimento?
artm

47
Spero che quel libro includesse questo come esempio di codice cattivo o deliberatamente oscuro.
Jon Hanna,

31
@Daniel: Un'altra idea sarebbe quella di rand ()% 2 definire MAYBE come rand ()% 2, quindi a volte è == TRUE e talvolta == FALSE.
Kaiserludi,

Risposte:


380

Vediamo: '/' / '/'significa charletterale /, diviso per il charletterale '/'stesso. Il risultato è uno, che suona ragionevole TRUE.

E '-' - '-'significa charletterale '-', sottratto da se stesso. Questo è zero ( FALSE).

Ci sono due problemi con questo: in primo luogo, non è leggibile. Utilizzando 1ed 0è assolutamente migliore. Inoltre, come hanno sottolineato TartanLlama e KerrekSB, se hai mai intenzione di utilizzare quella definizione, ti preghiamo di aggiungere parentesi attorno a loro in modo da non avere sorprese:

#include <stdio.h>

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

int main() {
        printf ("%d\n", 2 * FALSE);
        return 0;
}

Questo stamperà il valore del valore charletterale '-'(45 sul mio sistema).

Tra parentesi:

#define TRUE  ('/'/'/')
#define FALSE ('-'-'-')

il programma stampa correttamente zero, anche se non ha molto senso moltiplicare un valore di verità per un numero intero, ma è solo un esempio del tipo di bug imprevisti che potrebbero morderti se non parentesi le tue macro.


6
Accidenti ho preso molto per capirlo: s pensavo addirittura che fosse una cosa strana come glifi ... non so xD
Luis Masuelli,

8
In realtà ha senso moltiplicarsi con il valore di verità. Per esempio, il rientro * should_indent comporterà 0 o rientro in base al fatto che should_indent senza ramificazione. (Immagino che questo non sia un buon esempio, quando si lavora con il testo a ramificazione singola non ha importanza (ho visto questa tecnica negli shader e in XPATH (entrambi troppo diversi e non ricordo la forma esatta))
Alpedar

2
Alpedar - ma concettualmente e matematicamente non ha senso farlo - in questo caso sarebbe più chiaro (e concettualmente sensato) usare un ifinvece di moltiplicare TRUEper un numero intero.
Jay,

4
Ottima spiegazione Prendi un distintivo d'oro!
Michael Hampton,

2
La negazione logica potrebbe essere implementata come notx = TRUE- x;e funziona bene. Tranne che TRUE-FALSEè -44 (supponendo ASCII)
Hagen von Eitzen il

89

È solo un altro modo di scrivere

#define TRUE 1
#define FALSE 0

L'espressione '/'/'/'dividerà il valore del carattere '/'per se stesso, il che darà 1 come risultato.

L'espressione '-'-'-'sottrarrà il valore del carattere di '-'da se stesso, che darà come risultato 0.

Mancano parentesi attorno a tutte le defineespressioni, il che può portare a errori nel codice usando queste macro. La risposta di Jay si rivolge piuttosto bene.

Un esempio di scenario di "vita reale" in cui dimenticare le parentesi può essere dannoso è l'uso combinato di queste macro con un operatore di cast di tipo C. Se qualcuno decide di trasmettere queste espressioni boolin C ++ per esempio:

#include <iostream>

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

int main() {
    std::cout << "True: " << (bool) TRUE << std::endl;
    std::cout << "False: " << (bool) FALSE << std::endl;
    return 0;
}

Ecco cosa otteniamo:

True: 0
False: -44

Quindi (bool) TRUEvaluterei effettivamente falsee (bool) FALSEvaluteremmo true.


4
L'esempio è bello :)
Kit Fisto

44

È equivalente alla scrittura

#define TRUE 1
#define FALSE 0

Quello che '/'/'/'effettivamente fa l'espressione è dividere il personaggio /(qualunque sia il suo valore numerico) da solo, così diventa 1.

Allo stesso modo, l'espressione '-'-'-'sottrae il personaggio -da se stessa e valuta 0.

Sarebbe meglio scrivere

#define TRUE ('/'/'/')
#define FALSE ('-'-'-')

per evitare la modifica accidentale dei valori se utilizzato con altri operatori con precedenza superiore.


5
LOL! Ecco perché le macro devono essere correttamente tra parentesi.
0605002,

3 diritti su una sfera e
finisci

@KerrekSB No, ma tre sinistre lo fanno :)
Tim Long

33

Jay ha già risposto perché i valori di queste espressioni sono 0e 1.

Per amor di storia, queste espressioni '/'/'/'e '-'-'-'provengono da una delle voci del 1 ° Concorso internazionale per codice C offuscato nel 1984 :

int i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++"hell\
o, world!\n",'/'/'/'));}read(j,i,p){write(j/p+p,i---j,i/i);}

(Link al programma qui , c'è un suggerimento su cosa fa questo programma nella pagina IOCCC sopra.)

Anche se ricordo correttamente queste espressioni come macro offuscate per TRUEe FALSEsono state anche trattate nel libro "Obfuscated C and Other Mysteries" di Don Libes (1993).


7

È un modo esilarante per scrivere macro per Truee False.

Poiché sono state fornite molte spiegazioni /significa un numero di 1 byte (come da ASCII) quando diviso per se stesso ti dà 1quale sarà trattato come Truee allo stesso modo -è di nuovo un numero di byte quando viene sottratto lo stesso valore che ti dà 0che verrà interpretato comefalse

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

quindi possiamo sostituire /o -con qualsiasi carattere che ci piace, ad esempio:

#define TRUE  '!'/'!'
#define FALSE 'o'-'o'

Manterrà lo stesso significato dell'espressione originale.


6

Cominciamo con vero. Puoi leggerlo come '/' / '/', che significa "carattere" / "diviso per carattere" / "". Poiché ogni carattere, in C, è un valore numerico (su un byte), può essere letto come "il valore ASCII del carattere '/' diviso per il valore ASCII dello stesso carattere", che significa 1 (perché, ovviamente, x / x è 1). Quindi, TRUEè 1.

Per FALSE lo stesso ragionamento: '-'-'-'legge '-' - '-', cioè "il valore ASCII di '-' meno il valore ASCII di '-'", che è 0. Quindi, FALSEè 0.

Questo è un modo brutto per affermare l'ovvio.


7
Questo non ha nulla a che fare con ASCII.
Kerrek SB,

6
@Fabien: non dipende da ASCII. '/'/'/'è 1 per qualsiasi set di caratteri valido, sia '/' == 47(come in ASCII), sia '/' == 97(come in EBCDIC) o qualsiasi altro valore.
Keith Thompson,

4
@Pawel: Un'implementazione conforme C non può mappare '/'a 0. Tale valore è riservato al carattere null.
Keith Thompson,

2
Sei pedante.
Matheus208,

3
@ Matheus208 Se Pawel era pedante, allora quello è ('-'-'-') poiché il suo punto era basato su una condizione non dichiarata; descrivere le osservazioni di Keith come pedanti potrebbe essere più ('/' / '/') ma le definirei "chiarificanti" (e con le faccine aggiunte "pedanti" mi sembra decisamente "/" - "/"). Può essere ('-' / '-') che i commenti presi insieme possano essere chiamati pedanti ma, 1) non è un po 'obbligatorio in questo campo? 2) mi hanno fatto pensare; e 3) Sono un po 'più chiaro su alcune cose di quanto non fossi. E sì, immagino di essere me stesso pedante! (Ma sono più chiaro su cosa significhi "pedante" di me! ;-)
Zhora,
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.