Handhabung von bool in C/C++

  • C

Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von Thunderbolt.

    Handhabung von bool in C/C++

    Ich hab mich immer schon gefragt, wie das gehandhabt wird.

    Trade schrieb:

    C-Quellcode

    1. typedef int bool;
    2. #define true 1
    3. #define false 0

    Würde das nicht bedeuten, dass if (!true) {...} trotzdem ausgeführt werden würde?

    Hab gerade recherchiert. c = !a; ist vom Prinzip her wie c = (a == 0) ? 1 : 0;, deshalb funktioniert das.
    Aber was passiert da auf Assembler-Ebene bei den ganzen logischen Operatoren?

    C-Quellcode

    1. c = !a;
    2. c = a & b;
    3. c = a | b;
    4. c = a ^ b;

    Wird da überall auf Un/Gleichheit mit 0 geprüft? Das würde doch merkbar auf die Performance gehen, oder?
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Trade“ ()

    Moment. Das wäre dann inkonsistent.

    C-Quellcode

    1. if ((SomeObject*)2) {...]

    Das dürfte dann nicht ausgeführt werden, den das letzte Bit ist nicht gesetzt.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Also ich weiß nicht, ob wir der Sache näher kommen, oder ob wir uns im Kreis drehen, aber:

    C-Quellcode

    1. typedef int bool;
    2. #define true 1
    3. #define false 0


    Also ich geh's nochmal langsam durch:
    • if prüft auf != 0
    • bools sind intern ints (oder einzelne bytes)
    • (bool)15 ist genauso gültig wie (bool)1 und wird von if als true interpretiert.
    • (int)(bool)a ergibt 15
    • (int)(bool)b ergibt 1
    • !x ist das Äquivalent von x == 0 ? 1 : 0
    • Was ist das Äquivalent von x & y? Eine von diesen Möglichkeiten?:
      • x == 0 ? 0 : (y == 0 ? 0 : 1) behandelt bools korrekt, ints aber nicht
      • ganz normales bitweises and, wie man es von ints kennt, welches ints richtig behandelt, bools aber nicht, denn 2 & 4 wäre 0, was als false interpretiert wird, obwohl beide Operanden als true interpretiert werden



    Edit:
    @Trade
    Dem stimme ich zu.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Niko Ortner“ ()

    Ich habe mir mal erlaubt, das auszulagern, da es ja doch eine programmierspezifische Frage ist. ^^
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Ich schätze das ist ne Ansichtssache.
    Ein bool mag als int repräsentiert werden, aber das macht nicht jeden int zu einem bool. Ich bin mir deswegen ziemlich sicher, dass es schlechtes Design wäre, für einen bool-Rückgabewert was anderes als 1 oder 0 zurückzugeben. Wenn was anderes rauskommen kann würde man gleich nen int zurückgeben, keinen bool. Damit blieben alle Werte in komplexerer bool-Logik auf 0 und 1 beschränkt.
    Der Quirk, dass alle ints <> 0 als true interpretiert werden erlaubt mehr für bestimmte Schleifenkonstrukte und dergleichen, sodass keine zusätzlichen Konvertierungen erforderlich sind. Wenn man mit booleschen Werten hantiert, die rein als solche betrachtet werden und nicht ihren Ursprung als ints haben, halte ich es für best practice, sich auf 0 und 1 zu beschränken.

    Du musst bedenken: C++ ist nicht C#. C++ ist nicht so streng stark typisiert wie C#. C++ tauscht für Performance einiges an Restriktionen ein (siehe z.B. Templates vs Generics).
    Davon abgesehen, dass C# stark typisiert ist, gäbe es auch keinen wirklichen Sinn, Booleans so wie in C++ zu implementieren, da es u.a. keine Pointer gibt (zumindest als Sprachfeature direkt), die man auf 0 setzen und entsprechend prüfen könnte.

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    1. if prüft vmtl eher auf 0:

    Quellcode

    1. jz a,label//if a
    2. //a ist true
    3. endelse:

    bzw.

    Quellcode

    1. jz a,label//if a
    2. //a ist true
    3. jmp endelse
    4. else:
    5. //a ist false
    6. endelse:

    ist denke ich besser umgesetzt als umgekehrt:

    Quellcode

    1. jnz a,iflabel
    2. //else block(a ist false)
    3. jmp endiflabel
    4. iflabel:
    5. //a ist true
    6. endiflabel:

    natürlich macht es ansich überhaupt keinen unterschied, aber besser lesbar ist es allemal, kann natürlich dadurch optimieren, falls einer der beiden Fälle häufiger vorkommt, da man dann sich nen Sprung sparen könnte. Dieser Code ist natürlich ohne gewähr, ich hab keine Ahnung ob ein Compiler das so umsetzt.
    2. bools werden meist als ints interpretiert mit der größe jeweiligen Speicherzellen größe(also Architektur) um somit das alignment direkt zu erledigen und den Zugriff auf die werte möglichst performant zu gestalten.
    3.!x wird so ähnlich funktionieren, wobei ich mir ziemlich sicher bin, dass das intern über einfache Befehle gemacht wird ohne einen Jump.
    sowas in die Richtung vielleicht.

    Quellcode

    1. cmp a,0x0
    2. sete b,0x1


    4.Deine casts stimmen nur bedingt. Wenn du stdbool verwendest, dann ist der Compiler in der Regel schlauer und macht aus deinen ints bei einem cast automatisch ein bool mit dem Wertebereich {0;1}

    Quellcode

    1. cmp a,0x0
    2. setne b,0x1//unterschied zum ! operator

    -> die Verundung kann ganz normal bitwise stattfinden und die ganze bool logik wird funktionieren.
    Jedoch wird deine int Logik natürlich nicht funktionieren, da bei einem bool cast genau diese Information bereits verloren geht.
    (Umgekehrt sieht das ganze natürlich aus, wenn du es mit einfachen typedefs selbst definiert, dann wird alles weiterhin wie ints behandelt)
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Ja, ich stimme Euch da zu, dass man sich auf 0 und 1 beschränken sollte. Aber irgendwas "magisches" muss ja passieren, denn alle Werte != 0 sind auch gültige Booleans und es wäre komisch, wenn die Verknüpfungsoperatoren plötzlich nicht richtig funktionieren würden.

    Edit: Race Condition mit Post #11

    Edit 2:
    Also wenn ich das richtig verstehe, kommt man bei normaler Verwendung gar nicht erst auf problematische Werte (und deshalb funktionieren die logischen Operatoren auch wie erwartet).
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Niko Ortner“ ()

    C++ ist 100% typisiert. Dort gibts auch einen eigenen Datentyp, nämlich bool. Der ist exakt 1 byte groß und kein int. Aus Kompatibilität mit C läuft bei if alles != 0 durch. Was ja auch absolut sinnig ist, um z.B. Zeiger auf Validität zu prüfen. In C wird einfach n int genommen.

    Artentus schrieb:

    Da nur das letzte Bit betrachtet wird ist es effektiv die selbe Operation.
    in C / C++.
    Mal als Einwurf: In den alten BASIC-Dialekten war TRUE = -1, d.h., alle Bits waren gesetzt, da hat das mit NOT & Co anders funktioniert.
    @Niko Ortner Du kannst ja mal ein Snippet kompilieren und im Assemblercode debuggen, da müsste dann klar sein, wie das umgesetzt wird.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!