posts - 644, comments - 2003, trackbacks - 137

My Links

News

Raffaele Rialdi website

Su questo sito si trovano i miei articoli, esempi, snippet, tools, etc.

Archives

Post Categories

Image Galleries

Blogs

Links

Bug del compilatore VC++2003 su const volatile

... bug che non è presente in VC++2005.

Il linguaggio C++ mette a disposizione molte keyword che non sono indispensabili ma che rendono il sorgente più leggibile e rendono possibile un controllo più ferreo da parte del compilatore.

Per esempio const serve per rendere read-only una variabile. Il compilatore permette quinidi la sua inizializzazione ma ci restituisce un errore di compilazione qualora provassimo ad assegnare il suo valore successivamente.

Questo è un grosso benefit del compilatore perchè gli errori del compilatore sono nostri amici. Tutto ciò che ci viene rilevato in compilazione, ci evita grossi problemi successivamente ed è questo il motivo per cui keyword come const andrebbero sempre usate per rendere più rigoroso il sorgente.

L'uso di const per esempio fornisce un'immediato guadagno in performance perché il compilatore metterà direttamente il valore della costante nel nostro sorgente invece di eseguire l'accesso in memoria alla variabile, risparmiando così un'istruzione.

Può capitare però di avere un dispositivo hardware, un driver, una zona in shared memory che modifica il valore della variabile dichiarata const, anche se dal nostro sorgente non la modificheremo mai. A questo scopo esiste la keyword volatile. In pratica avvisa il compilatore di non eseguire alcuna ottimizzazione perchè il valore di quella variabile può cambiare al di là di quello che può fare il listato.

Il seguente sorgente, una semplice console Win32 riproduce il bug del compilatore VC++2003.

#include "stdafx.h"
#include <iostream>
int _tmain(int argc, _TCHAR* argv[])
{
   const volatile int iTest = 1;
   _asm
   {
      push 5
      pop iTest
   }

   if(argc == iTest)
      std::cout << "equals!";
   return 0;
}

Compilato con VC++ 2003 il risultato è questo (per maggiore chiarezza pubblico con il sorgente misto C++ e compilato x86):

 const volatile int iTest = 1;
00415D2E C7 45 F8 01 00 00 00 mov         dword ptr [iTest],1

 _asm
 {
  push 5
00415D35 6A 05            push        5   
  pop iTest
00415D37 8F 45 F8         pop         dword ptr [iTest]
 }

 if(argc == iTest)
00415D3A 83 7D 08 01      cmp         dword ptr [argc],1 
// BUG! Ha sostituito iTest con 1 anche se è volatile
00415D3E 75 12            jne         main+42h (415D52h)
  std::cout << "equals!";
00415D40 68 C8 00 44 00   push        offset string "equals!" (4400C8h)
00415D45 68 D8 92 44 00   push        offset std::cout (4492D8h)
00415D4A E8 DA EB FF FF   call        std::operator<<<std::char_traits<char> > (414929h)
00415D4F 83 C4 08         add         esp,8

 return 0;
00415D52 33 C0            xor         eax,eax

Compilato con VC++ 2005 il risultato è questo:

 const volatile int iTest = 1;
0041140E C7 45 F8 01 00 00 00 mov         dword ptr [iTest],1

 _asm
 {
  push 5
00411415 6A 05            push        5   
  pop iTest
00411417 8F 45 F8         pop         dword ptr [iTest]
 }

 if(argc == iTest)
0041141A 8B 45 F8        
mov         eax,dword ptr [iTest]
0041141D 39 45 08         cmp         dword ptr [argc],eax
00411420 75 13            jne         wmain+45h (411435h)
  std::cout << "equals!";
00411422 68 FC 66 41 00   push        offset string "equals!" (4166FCh)
00411427 A1 A8 92 41 00   mov         eax,dword ptr [__imp_std::cout (4192A8h)]
0041142C 50               push        eax 
0041142D E8 FF FC FF FF   call        std::operator<<<std::char_traits<char> > (411131h)
00411432 83 C4 08         add         esp,8

 return 0;
00411435 33 C0            xor         eax,eax

In sostanza VC++ 2003 ignora la keyword volatile e di conseguenza non è usabile più allo scopo.

L'uso dell'inline assembler simula la presenza di un “qualcosa“ di esterno che modifichi la variabile. Al posto del blocco _asm ci sarebbe potuta essere una shared memory o qualsiasi altra cosa.

Per dovere di cronaca va detto che questa ottimizzazione viene fatta sia in modalità release che in debug (cioè con le ottimizzazioni 'spente'). Ci sono però tante ottimizzazioni più spinte che vegnono effettuate solo in modalità release e per questo è sempre indispensabile fare i test anche sulla versione release.

Print | posted on martedì 26 luglio 2005 20:31 | Filed Under [ C++ [Italiano] ]

Feedback

Gravatar

# re: Bug del compilatore VC++2003 su const volatile

Interessante il modo di "decorare" a livello IL un campo come volatile, utilizzando una "marker class" (classe senza membri propri) System.Runtime.CompilerServices.IsVolatile
27/07/2005 20:01 | Adrian Florea
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET