Attenzione quando si confrontano i riferimenti a bool e int con MSVC 2015

Il seguente codice genera un avviso con MSVC (2015 Update 3) – con /W4 :

 const bool& a = true; const int& b = 1; if(a == b) 

C4805: '==': unsafe mix of type 'const bool' and type 'const int' in operation

ma senza i riferimenti si compila in modo pulito.

 const bool a = true; const int b = 1; if(a == b) 

PERCHÉ?

MODIFICARE:

appena testato senza const pure

 bool a = true; int b = 1; if(a == b) 

e l’avvertimento è riapparso …

MODIFICA 2:

Compilando in Debug … Ho dovuto mettere a tacere C4127: conditional expression is constant nel caso const noref però …

MODIFICA 3:

ecco i disassemblaggi per i 3 casi:

const ref

 0113BA92 in al,dx 0113BA93 sub esp,24h 0113BA96 mov eax,0CCCCCCCCh 0113BA9B mov dword ptr [ebp-24h],eax 0113BA9E mov dword ptr [ebp-20h],eax 0113BAA1 mov dword ptr [ebp-1Ch],eax 0113BAA4 mov dword ptr [ebp-18h],eax 0113BAA7 mov dword ptr [b],eax 0113BAAA mov dword ptr [ebp-10h],eax 0113BAAD mov dword ptr [ebp-0Ch],eax 0113BAB0 mov dword ptr [ebp-8],eax 0113BAB3 mov dword ptr [a],eax const bool& a = true; 0113BAB6 mov byte ptr [ebp-9],1 0113BABA lea eax,[ebp-9] 0113BABD mov dword ptr [a],eax const int& b = 1; 0113BAC0 mov dword ptr [ebp-1Ch],1 0113BAC7 lea ecx,[ebp-1Ch] 0113BACA mov dword ptr [b],ecx if(a == b) 0113BACD mov edx,dword ptr [a] 0113BAD0 movzx eax,byte ptr [edx] 0113BAD3 mov ecx,dword ptr [b] 0113BAD6 cmp eax,dword ptr [ecx] 0113BAD8 jne DOCTEST_ANON_FUNC_2+5Fh (0113BAEFh) throw 5; 0113BADA mov dword ptr [ebp-24h],5 0113BAE1 push offset __TI1H (0117318Ch) 0113BAE6 lea edx,[ebp-24h] 0113BAE9 push edx 0113BAEA call [email protected] (01164B04h) 

solo const

 0137BA92 in al,dx 0137BA93 sub esp,0Ch 0137BA96 mov dword ptr [ebp-0Ch],0CCCCCCCCh 0137BA9D mov dword ptr [b],0CCCCCCCCh 0137BAA4 mov dword ptr [ebp-4],0CCCCCCCCh const bool a = true; 0137BAAB mov byte ptr [a],1 const int b = 1; 0137BAAF mov dword ptr [b],1 if(a == b) 0137BAB6 mov eax,1 0137BABB test eax,eax 0137BABD je DOCTEST_ANON_FUNC_2+44h (0137BAD4h) throw 5; 0137BABF mov dword ptr [ebp-0Ch],5 0137BAC6 push offset __TI1H (013B318Ch) 0137BACB lea ecx,[ebp-0Ch] 0137BACE push ecx 0137BACF call [email protected] (013A4B04h) 

no const no ref

 0012BA92 in al,dx 0012BA93 sub esp,0Ch 0012BA96 mov dword ptr [ebp-0Ch],0CCCCCCCCh 0012BA9D mov dword ptr [b],0CCCCCCCCh 0012BAA4 mov dword ptr [ebp-4],0CCCCCCCCh bool a = true; 0012BAAB mov byte ptr [a],1 int b = 1; 0012BAAF mov dword ptr [b],1 if(a == b) 0012BAB6 movzx eax,byte ptr [a] 0012BABA cmp eax,dword ptr [b] 0012BABD jne DOCTEST_ANON_FUNC_2+44h (012BAD4h) throw 5; 0012BABF mov dword ptr [ebp-0Ch],5 0012BAC6 push offset __TI1H (016318Ch) 0012BACB lea ecx,[ebp-0Ch] 0012BACE push ecx 0012BACF call [email protected] (0154B04h) 

Quindi sembra che ci sia un salto per l’istruzione if, quindi non è ottimizzato e non viene diagnosticato in caso di errore (debug config) …

Questo è ciò che accade con GCC 6.1 per il seguente codice:

 int ref(int num) { const bool& a = true; const int& b = 1; return a == b; } int noref(int num) { const bool a = true; const int b = 1; return a == b; } int noref_noconst(int num) { bool a = true; int b = 1; return a == b; } 

Produzione di assembly:

 ref(int): pushq %rbp movq %rsp, %rbp movl %edi, -36(%rbp) movl $1, %eax movb %al, -21(%rbp) leaq -21(%rbp), %rax movq %rax, -8(%rbp) movl $1, %eax movl %eax, -20(%rbp) leaq -20(%rbp), %rax movq %rax, -16(%rbp) movq -8(%rbp), %rax movzbl (%rax), %eax movzbl %al, %edx movq -16(%rbp), %rax movl (%rax), %eax cmpl %eax, %edx sete %al movzbl %al, %eax popq %rbp ret noref(int): pushq %rbp movq %rsp, %rbp movl %edi, -20(%rbp) movb $1, -1(%rbp) movl $1, -8(%rbp) movl $1, %eax popq %rbp ret noref_noconst(int): pushq %rbp movq %rsp, %rbp movl %edi, -20(%rbp) movb $1, -1(%rbp) movl $1, -8(%rbp) movzbl -1(%rbp), %eax cmpl -8(%rbp), %eax sete %al movzbl %al, %eax popq %rbp ret 

La cosa più semplice da notare qui sul assembly è che nel caso di noref non c’è nemmeno un salto; è solo un semplice return 1 .

La stessa cosa sta probabilmente accadendo in MSVC, che poi scivola oltre il meccanismo di rilevamento degli avvertimenti, e semplicemente non ne ottieni uno.

MODIFICARE:

Diamo un’occhiata al vostro assembly e alla sola versione const in particolare:

  if(a == b) 0137BAB6 mov eax,1 0137BABB test eax,eax 0137BABD je DOCTEST_ANON_FUNC_2+44h (0137BAD4h) 

Mentre è vero che l’istruzione if ( je ) è lì, possiamo vedere che in realtà non confronta le variabili – che è l’operazione precisa che triggers l’avviso. Mette semplicemente 1 in un registro e poi confronta il registro con se stesso.