首先簡單介紹一下編譯器對代碼優化的概念:
編譯器優化:在不影響程式結果的情況下,改變程式的執行順序提高效率
優化級别有:
O0 O1 O2 O3
優先級别越高,優化的越厲害
如何優化?在此介紹volatile,我們隻談優化的一個方式,就是将頻繁使用的變量直接加載到離cpu很近的寄存器中。
我們先來看如下代碼:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int flag=1;
void Handler(int signo){
printf("signo=%d\n",signo);
flag=0;
}
int main(){
signal(2,Handler);
while(flag){}
}
在不優化的情況下直接進行編譯,我們可預見:程式運作起來,當給這個程序發送二号信号flag值才會變為0使循環結束程式運作結束。
但當用O2使編譯器對這個代碼進行優化時,就會發現按下ctrl+c發送2号信号時,循環依舊不會停止。這是為什麼呢?
原來:
在編譯器在優化過程中,若編譯器判定某個資料是一個比較高的開銷,然後編譯器沒有檢測到有代碼修改這個資料,便會把頻繁使用的資料放到了寄存器中(while循環頻繁使用flag,Handle函數雖對他進行修改但是由核心調用的,編譯器并不知道),編譯器就可能作出了錯誤的判斷,這時就直接把flag這個值優化到寄存器裡了,Handle函數對flag的修改隻是改變了記憶體中的flag并沒有改變寄存器中的flag,因而while判斷時用到寄存器中的flag一直是1.是以循環就結束不了。
為了避免這種編譯器的錯誤決措,我們引入volatile關鍵字
這個關鍵字修飾變量就是告訴編譯器,這個變量必須每次都從記憶體中讀,不敢直接加載到寄存器中,即volatile的目的就是保持記憶體可見性
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
volatile int flag=1;
void Handler(int signo){
printf("signo=%d\n",signo);
flag=0;
}
int main(){
signal(2,Handler);
while(flag){}
}