對C語言的volatile關鍵字的理解


    volatile在英語的意思是:揮發性的, 不穩定的, 易變的. 在編程中不是是很容易被理解的它, 加上平常很少被用到, 再加上它更多地被用於硬件編程方面, 所以就更加讓一些人琢磨不透了.
    總之, 作為一個變量類型修飾符, volatile的作用就是被設計用來修飾被不同線程訪問和修改的變量. 在原子操作中同樣會用到. 如果沒有它, 很有可能使得編程寫的多線程程序出現不可預期的錯誤, 也可能因為編譯器的各種優化而導致編譯后的結果表達了不同的意思, 使得程序出現難以發現的錯誤.
    被volatile修飾的變量是說這個變量可能會被意想不到地被改變, 這樣, 編譯器就不會在編譯會訪問該變量的語句的時候, 依然使用保存在某個寄存器的值來加快速度, 取而代之的是, 每次都從該變量的原始地址處重新讀取該變量的值, 這樣就能使得取到的值總是是"最新"的, 真正意義上的最新. 區別在於:如果編譯器在編譯涉及到訪問某個變量的值的時候, 它會把被頻繁訪問的變量保存到CPU的寄存器中供復用, 以加快再次訪問變量的速度. 但是, 該值是從CPU的寄存器中取出的, 它雖然是最原始的值, 但如果在其它時間, 其它地點的程序如果修改了該變量的值, 那么編譯器拿到的值就是一個"過時"的值, 這樣就會出現錯誤. 其它時間可以是CPU的線程調度, 其它地點可以是另一個線程的代碼.
    下面看一點C語言例子.

    int main(void)
    {
        int i;
        i = 1;
        i = 2;
        return i;
    }

    在Debug模式(無任何優化)下, 生成的32位匯編代碼(省略其它代碼)為:

        ; i = 1
        mov dword ptr[ebp-4],1
        ; i = 2
        mov dword ptr[ebp-4],2
        ; return i
        mov eax,dword ptr[ebp-4]
        ret

        可見, 對i的每次賦值都會產生一條匯編語句來對應, 這完全同C程序意思.
    而當生成模式改成Release(優化被打開; 可能需要在項目設置中鈎上"生成調試信息")后,對應如下(省略其它代碼):

        mov eax,2
        ret

        可見, 多余的賦值代碼都被優化掉了, 這就是編譯器的優化措施.
    好的, 我們再把源代碼改成如下形式:

        int main(void)
        {
            volatile int i;
            i = 1;
            i = 2;
            return i;
        }

    修改后, Debug生成的匯編代碼沒有變化, 但Release生成的代碼卻變成了:

        push ecx
        mov dword ptr[esp],1
        mov dword ptr[esp],2
        mov eax,dword ptr[esp]
        pop ecx

        可見, 加了volatile后, 就算打開優化, 編譯器也不會作優化, 每次取值都是重新取值, 雖然在這里所有語言直接一條return 2;就可以代替, 但編譯器卻沒有那樣做~
    
    
    另一個典型的例子, 可能很多人用於延時,測試速度:

        int i;
        for(i=0; i<10000; i++)
            ;

        在debug模式下, 語句會完完整整地執行10000次. 絲毫不差.
        在release下, 這條語句直接就沒有了, 不信的話可以自己試試.
        加上 volatile 后就同debug一樣了. 語句才會被執行.
        也就是說, 加上volatile關鍵字, 相當於程序員告訴編譯器:you! 你不能認為在當前程序塊中它不會有什么用, 但在其它地方, i的值可能被程序修改, 程序的運行狀態跟外界有關, 你不能優化它, 原原本本地執行它!

女孩不哭(QQ:191035066)@2012-12-19 21:18:20 http://www.cnblogs.com/nbsofer



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM