简体   繁体   中英

Difference between extern and volatile

This question regards the difference between the volatile and extern variable and also the compiler optimization.

One extern variable defined in main file and used in one more source file, like this:

ExternTest.cpp:

short ExtGlobal;
void Fun();

int _tmain(int argc, _TCHAR* argv[])
{

    ExtGlobal=1000;
    while (ExtGlobal < 2000)
    {
        Fun();
    }
    return 0;
}

Source1.cpp:

extern short ExtGlobal;

void Fun()
{
    ExtGlobal++;
}

The assembly generated for this in the vs2012 as below:

ExternTest.cpp assembly for accessing the external variable

ExtGlobal=1000;
013913EE  mov         eax,3E8h  
013913F3  mov         word ptr ds:[01398130h],ax  

while (ExtGlobal < 2000)
013913F9  movsx       eax,word ptr ds:[1398130h]  
01391400  cmp         eax,7D0h  
01391405  jge         wmain+3Eh (0139140Eh) 

Source.cpp assembly for modifying the extern variable

ExtGlobal++;
0139145E  mov         ax,word ptr ds:[01398130h]  
01391464  add         ax,1  
01391468  mov         word ptr ds:[01398130h],ax  

From the above assembly, every access to the variable "ExtGlobal" in the while loop reads the value from the corresponding address. If i add volatile to the external variable the same assembly code was generated. Volatile usage in two different threads and external variable usage in two different functions are same.

Asking about extern and volatile is like asking about peanuts and gorillas. They're completely unrelated.

extern is used simply to tell the compiler, "Hey, don't expect to find the definition of this symbol in this C file. Let the linker fix it up at the end."

volatile essentially tells the compiler, "Never trust the value of this variable. Even if you just stored a value from a register to that memory location, don't re-use the value in the register - make sure to re-read it from memory."

If you want to see that volatile causes different code to be generated, write a series of reads/writes from the variable.

For example, compiling this code in cygwin, with gcc -O1 -c ,

int i;

void foo() {
    i = 4;

    i += 2;

    i -= 1;
}

generates the following assembly:

_foo proc near
mov     dword ptr ds:_i, 5
retn
_foo endp

Note that the compiler knew what the result would be, so it just went ahead and optimized it.

Now, adding volatile to int i generates the following:

public _foo
_foo proc near
mov     dword ptr ds:_i, 4

mov     eax, dword ptr ds:_i
add     eax, 2
mov     dword ptr ds:_i, eax

mov     eax, dword ptr ds:_i
sub     eax, 1
mov     dword ptr ds:_i, eax

retn
_foo endp

The compiler never trusts the value of i , and always re-loads it from memory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM