2015-07-16 15 views
14

ho riprodurre il problema da questo semplice demo:bug g ++? (Bool_val 0: 1) restituisce né 0 né 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 compilare ed eseguire:

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

-O1 compilare ed eseguire (inaspettato risultato):

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

Quando controllo il codice -O2 ASM, ritengo sia un errore g ++, g ++ 's optimzation codice pensare sempre il valore booleano è un etere 1 o 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)

È questo comportamento g ++ in base alla progettazione? Come posso disattivare questa ottimizzazione errata? Grazie ~

+0

gcc versione 4.9.2 (Debian 4.9.2-10) – mikewei

+5

Interessante '# include'. – erip

+12

L'ottimizzazione non è sbagliata: un bool può contenere solo 0 o 1. Quello che stai passando è un tipo "int" punito come "bool", ne deriva un comportamento indefinito. – Quentin

risposta

49

Penso che sia un bug g ++.

Devono rispettosamente non essere d'accordo.

Come disattivare questa ottimizzazione errata?

Anche se questo è possibile, non è in realtà :-) sbagliato

si passa un puntatore non bool come un puntatore bool (l'elemento di fondo non è di tipo bool) e sono abbastanza certo che questo (noto come punire tipo) invoca un comportamento indefinito.

Quindi il codice è libero di fare quello che vuole.

si può pensare del prototipo void func(bool* b) come contratto l'utente accetta di passare sempre e solo i puntatori ai bool valori. Se si viola quel contratto, tutte le scommesse sono spente. In questo caso particolare, il codice:

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

sta dicendo per convertire falso a 1 e fedele a 0. Se si dovesse fornire valida ingresso (false/0 o true/1), il xor input, 1 sarebbe esattamente la cosa giusta da fare.

Tuttavia, poiché lo si sta dando 128, i risultati xor in 129.

+0

Concordato. L'implementazione sembra implementare un valore bool con valori 0 e 1. Pertanto, purché i tipi di bool siano sempre e solo usati, possono essere facilmente manipolati con xor. Anche la conversione in int è semplice, poiché il bool sottostante sembra essere un int, quindi non è necessaria alcuna operazione di conversione. – djgandy

+5

Questo è chiamato punire tipo, e lo standard vieta di digitare punning da int a bool (§3.10/10 in N3376). È davvero UB. –

+0

La parte finale della domanda è come disattivare l'ottimizzazione. Mentre sconsiglio vivamente di farlo e non sono d'accordo con la descrizione del questionario come "ottimizzazione sbagliata", ci sono ottimizzazioni denominate che gcc ti permette di disabilitare per scrivere codice che ha UB secondo lo standard. '-fno-delete-null-pointer-checks' è un famoso esempio. Non ho controllato ma '-fno-strict-aliasing'" corregge "questo codice? –

Problemi correlati