2015-07-16 19 views
14

ich reproduzieren das Problem durch diese einfache Demo:g ++ Fehler? (Bool_val 0: 1) gibt weder 0 noch 1

// bool_test_func.cpp 
#include <stdio.h> 

void func(bool* b) { 
    int a = (*b ? 0 : 1); 
    printf("%d\n", a); // EXPECT ether 0 or 1 here 
} 

// bool_test.cpp 
void func(bool* b); 

int main() { 
    int n = 128; 
    func((bool*)&n); 
    return 0; 
} 

-O0 kompilieren und ausführen:

g++ -g -O0 -Wall -o bool_test bool_test.cpp bool_test_func.cpp 
[email protected]:~/testing/c++$ ./bool_test 
0 

-O1 Kompilieren und Ausführen (unerwartet Ergebnis):

g++ -g -O1 -Wall -o bool_test bool_test.cpp bool_test_func.cpp 
[email protected]:~/testing/c++$ ./bool_test 
129 

Wenn ich den -O2 ASM-Code überprüfen, ich denke, es ist ein g ++ Fehler ist, g ++ 's optimzation Code denken immer, der Boolesche Wert Ether 1 oder 0:

 

    00000000004005e6 : 
     4005e6:  48 83 ec 08    sub $0x8,%rsp 
     4005ea:  0f b6 37    movzbl (%rdi),%esi 
     4005ed:  83 f6 01    xor $0x1,%esi #just XOR the bool val 
     4005f0:  40 0f b6 f6    movzbl %sil,%esi 
     4005f4:  bf 94 06 40 00   mov $0x400694,%edi 
     4005f9:  b8 00 00 00 00   mov $0x0,%eax 
     4005fe:  e8 9d fe ff ff   callq 4004a0 
     400603:  48 83 c4 08    add $0x8,%rsp 
     400607:  c3      retq 
     400608:  0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1) 
     40060f:  00 

gcc Version 4.9.2 (Debian 4.9.2-10)

Ist das g ++ Verhalten von Design? Wie kann ich diese falsche Optimierung deaktivieren? Danke ~

+0

gcc Version 4.9.2 (Debian 4.9.2-10) – mikewei

+5

Interessantes '# include'. – erip

+12

Die Optimierung ist nicht falsch: Ein Bool kann nur 0 oder 1 enthalten. Was du eingibst, ist ein "int" -Typ, der als "bool" markiert wird, undefiniertes Verhalten folgt. – Quentin

Antwort

49

Ich denke, es ist ein g ++ Bug.

Ich muss da respektvoll widersprechen.

Wie kann ich diese falsche Optimierung deaktivieren?

Auch wenn die möglich ist, ist es nicht eigentlich falsch :-)

Sie sind ein nicht-Bool Zeiger als Bool Zeiger vorbei (der zugrunde liegende Artikel ist nicht vom Typ Bool) und ich bin ziemlich sicher, dass dies (bekannt als Typ Punning) undefiniertes Verhalten aufruft.

Daher ist der Code frei zu tun, was er will.

können Sie denken an den Prototyp void func(bool* b) als Vertrag erklären Sie sich immer nur Hinweise auf bool Werte zu übergeben. Wenn Sie gegen diesen Vertrag verstoßen, sind alle Wetten ungültig. In diesem speziellen Fall Code:

int a = (*b ? 0 : 1); 

ist es zu sagen: 1 und wahr auf 0 falsch zu konvertieren Wenn Sie waren gültig Eingang (false/0 oder true/1) zu liefern, wäre die xor input, 1genau das richtige tun.

Sie geben jedoch 128, die xor Ergebnisse in 129.

+0

Einverstanden. Die Implementierung scheint einen bool mit den Werten 0 und 1 zu implementieren. Daher können Bool-Typen, solange sie nur verwendet werden, leicht mit xor manipuliert werden. Auch die Konvertierung in int ist einfach, da das zugrundeliegende Bool ein int zu sein scheint, so dass kein Konvertierungsvorgang notwendig ist. – djgandy

+5

Dies wird als Typ punning bezeichnet, und der Standard verbietet den Typ punning von int nach bool (§3.10/10 in N3376). Es ist in der Tat UB. –

+0

Der letzte Teil der Frage ist, wie Sie die Optimierung deaktivieren. Während ich stark davon abraten würde, dies zu tun und mit der Beschreibung des Fragestellers als "falsche Optimierung" nicht einverstanden zu sein, gibt es benannte Optimierungen, die gcc Ihnen ermöglicht, zu deaktivieren, um Code zu schreiben, der UB gemäß dem Standard hat. '-fno-delete-null-pointer-checks' ist ein bekanntes Beispiel. Ich habe es nicht überprüft, aber "-no-strict-aliasing" "repariert" diesen Code? –

Verwandte Themen