Seltsame Definitionen von TRUE- und FALSE-Makros


300

Ich habe die folgenden Makrodefinitionen in einem Codierungsbuch gesehen.

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

Da gab es keine Erklärung.

Bitte erklären Sie mir, wie diese als TRUEund funktionieren FALSE.


63
Ich denke, es ist nur eine lustige Art, TRUE als 1 und FALSE als 0 zu definieren
BlackDwarf

160
Beachten Sie, dass dies eine schreckliche Idee ohne Klammern um diese Ausdrücke ist. Ich meine, es ist eine schreckliche Idee mit ihnen, aber ohne dass Sie nur nach einer langen Nacht des Debuggens fragen.
TartanLlama

70
Darf ich das Codierungsbuch kennen, auf das Sie sich beziehen?
Artm

47
Ich hoffe, dass das Buch dies als Beispiel für schlechten oder absichtlich undurchsichtigen Code enthält.
Jon Hanna

31
@ Daniel: Eine andere Idee wäre, rand ()% 2 MAYBE als rand ()% 2 zu definieren, das ist also manchmal == TRUE und manchmal == FALSE.
Kaiserludi

Antworten:


380

Mal sehen: '/' / '/'bedeutet das charLiteral /, geteilt durch das charLiteral '/'selbst. Das Ergebnis ist eines, für das es vernünftig klingt TRUE.

Und '-' - '-'bedeutet die charwörtliche '-', von sich selbst subtrahiert. Dies ist Null ( FALSE).

Hier gibt es zwei Probleme: Erstens ist es nicht lesbar. Verwenden 1und 0ist absolut besser. Wie TartanLlama und KerrekSB bereits betont haben, sollten Sie diese Definition in Klammern setzen, damit Sie keine Überraschungen erleben:

#include <stdio.h>

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

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

Dadurch wird der Wert des charLiteral gedruckt '-'(45 auf meinem System).

Mit Klammern:

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

Das Programm gibt Null korrekt aus, obwohl es wenig sinnvoll ist, einen Wahrheitswert mit einer Ganzzahl zu multiplizieren. Es ist jedoch nur ein Beispiel für unerwartete Fehler, die Sie beißen können, wenn Sie Ihre Makros nicht in Klammern setzen.


6
Verdammt, ich habe viel gebraucht, um es zu verstehen: Ich dachte sogar, es wäre eine seltsame Sache als Glyphen ... weiß nicht xD
Luis Masuelli

8
Es ist tatsächlich sinnvoll, mit dem Wahrheitswert zu multiplizieren. Zum Beispiel führt ein Einzug * should_indent entweder zu 0 oder zu einem Einzug, je nachdem, ob should_indent ohne Verzweigung ist. (Ich denke, dass dies ein schlechtes Beispiel ist, wenn die Arbeit mit einer einzelnen Verzweigung von Text keine Rolle spielt (ich habe diese Technik in Shadern und in XPATH gesehen (beide zu unterschiedlich und ich erinnere mich nicht an die genaue Form))
Alpedar

2
Alpedar - aber es macht konzeptionell und matehmatisch keinen Sinn, dies zu tun - in diesem Fall wäre es klarer (und konzeptionell sinnvoll), eine zu verwenden, ifanstatt TRUEmit einer ganzen Zahl zu multiplizieren .
Jay

4
Tolle Erklärung. Habe ein goldenes Abzeichen!
Michael Hampton

2
Die logische Negation kann als implementiert werden notx = TRUE- x;und funktioniert einwandfrei. Nur dass TRUE-FALSEdas -44 ist (unter der Annahme von ASCII)
Hagen von Eitzen

89

Es ist nur eine andere Art zu schreiben

#define TRUE 1
#define FALSE 0

Der Ausdruck '/'/'/'teilt den Zeichenwert von '/'durch sich selbst, was als Ergebnis 1 ergibt.

Der Ausdruck '-'-'-'subtrahiert den Zeichenwert '-'von sich selbst, was als Ergebnis 0 ergibt.

Es definefehlen jedoch Klammern um die gesamten Ausdrücke, was zu Fehlern im Code führen kann, wenn diese Makros verwendet werden. Jays Antwort spricht das ziemlich gut an.

Ein Beispiel für ein "reales" Szenario, in dem das Vergessen der Klammern schädlich sein kann, ist die kombinierte Verwendung dieser Makros mit einem C-ähnlichen Cast-Operator. Wenn sich jemand entscheidet, diese Ausdrücke boolin C ++ umzuwandeln, zum Beispiel:

#include <iostream>

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

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

Folgendes bekommen wir:

True: 0
False: -44

So (bool) TRUEwürde bewerten tatsächlich zu false, und (bool) FALSEwürde evaluieren true.


4
Das Beispiel ist schön :)
Kit Fisto

44

Es ist gleichbedeutend mit Schreiben

#define TRUE 1
#define FALSE 0

Was der Ausdruck '/'/'/'tatsächlich tut, ist das Teilen des Zeichens /(unabhängig von seinem numerischen Wert) durch sich selbst, so dass es wird 1.

In ähnlicher Weise '-'-'-'subtrahiert der Ausdruck das Zeichen -von sich selbst und wertet es aus 0.

Es wäre besser zu schreiben

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

um versehentliche Änderungen von Werten bei Verwendung mit anderen Operatoren mit höherer Priorität zu vermeiden.


5
LOL! Aus diesem Grund sollten Makros in Klammern gesetzt werden.
0605002

3 Rechte auf einer Kugel und Sie landen am selben Ort
Derek 5 會 功夫

@ KerrekSB Nein, aber drei Linke tun :)
Tim Long

33

Jay hat bereits geantwortet, warum die Werte dieser Ausdrücke 0und sind 1.

Zur Geschichte willen, diese Ausdrücke '/'/'/'und '-'-'-'von einem der Einträge kommen 1st International Obfuscated C - Code Contest 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 zum Programm hier , es gibt einen Hinweis darauf, was dieses Programm auf der IOCCC-Seite oben tut.)

Auch wenn ich mich richtig erinnere, wurden diese Ausdrücke als verschleierte Makros für TRUEund FALSEwurden auch in dem Buch "Obfuscated C and Other Mysteries" von Don Libes (1993) behandelt.


7

Es ist eine lustige Art, Makros für Trueund zu schreiben False.

Da viele Erklärungen gegeben wurden, /bedeutet dies, dass eine 1-Byte-Zahl (gemäß ASCII), wenn sie durch sich selbst geteilt wird, 1die als behandelt wird, Trueund ebenfalls -eine Byte-Zahl ist, wenn derselbe Wert subtrahiert wird, den Sie erhalten, 0der als interpretiert wirdfalse

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

Daher können wir /oder -durch ein beliebiges Zeichen ersetzen , zum Beispiel:

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

Behält die gleiche Bedeutung wie der ursprüngliche Ausdruck.


6

Beginnen wir mit true. Sie können es als lesen '/' / '/', was "Zeichen '/' geteilt durch Zeichen '/'" bedeutet. Da jedes Zeichen in C ein numerischer Wert (auf einem Byte) ist, kann es als "der ASCII-Wert des Zeichens '/' geteilt durch den ASCII-Wert desselben Zeichens" gelesen werden, was 1 bedeutet (weil offensichtlich x / x ist 1). Daher TRUEist 1.

Denn es FALSEist die gleiche Argumentation:'-'-'-' liest '-' - '-', dh "der ASCII-Wert von '-' minus dem ASCII-Wert von '-'", der 0 ist. Daher FALSEist 0.

Dies ist eine böse Art, das Offensichtliche zu sagen.


7
Dies hat nichts mit ASCII zu tun.
Kerrek SB

6
@ Fabien: Es hängt nicht von ASCII ab. '/'/'/'ist 1 für jeden gültigen Zeichensatz, egal ob '/' == 47(wie in ASCII) oder '/' == 97(wie in EBCDIC) oder für einen anderen Wert.
Keith Thompson

4
@Pawel: Eine konforme C - Implementierung kann nicht zuordnen '/'zu 0. Dieser Wert ist für das Nullzeichen reserviert.
Keith Thompson

2
Du bist pedantisch.
Matheus208

3
@ Matheus208 Wenn Pawel pedantisch war, dann ist das ('-'-'-'), da sein Standpunkt auf einem nicht angegebenen Zustand beruhte; Keith 'Äußerungen als pedantisch zu beschreiben, mag mehr sein (' / '/' / '), aber ich würde sie "klarstellend" nennen (und mit den hinzugefügten Smileys scheint "pedantisch" mir definitiv' / '-' / 'zu sein). Es mag sein ('-' / '-'), dass die Kommentare zusammengenommen als pedantisch bezeichnet werden können, aber 1) ist das in diesem Bereich nicht etwas obligatorisch? 2) sie haben mich zum Nachdenken gebracht; und 3) Ich bin in einigen Dingen etwas klarer als ich. Und ja, ich glaube, ich bin selbst pedantisch! (Aber ich bin klarer darüber, was "pedantisch" bedeutet als ich! ;-)
Zhora
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.