[英]What is extern volatile pointer
什么是extern volatile指針。
extern volatile uint32 *ptr;
在這里,* ptr的行為是什么? 這究竟意味着什么?
而且,什么時候應該使用?
我試圖谷歌,但沒有得到任何滿意的答案,關於這個組合沒有太多的信息。
外部 和易失性關鍵字都可以獨立考慮。 這些關鍵字中的每一個的角色不與另一個關鍵字交互,因此可以獨立地詳細說明它們中的每一個,如下所述。
extern告訴編譯器ptr的實際定義是在另一個模塊中(另一個.c
)。 基本上,編譯器處理ptr的方式沒有太大變化 - 有extern只是告訴編譯器它不必在內存中為ptr保留一些空間,因為它在另一個.c
其他位置完成,並且它的實際內存位置將是稍后由鏈接器給出。
extern uint32 *ptr;
如果省略extern ,編譯器不會抱怨。 但是,稍后, 鏈接器在嘗試鏈接所有對象模塊以構建最終的可執行程序時,將拋出錯誤“ ptr已定義兩次”(因為它已在另一個.c
定義)。
uint32 *ptr;
volatile告訴編譯器ptr所在的內存位置可能被某些外部事件更改/修改,並且它(編譯器)不應該依賴於某些效率優化,例如考慮到ptr的值在一些范圍內不會改變這樣的事件可以是異步中斷,當CPU執行上述范圍時發生,並且修改ptr值。
通常(在評論中使用優化的C的虛擬匯編代碼),REGx是CPU寄存器,我們對變量y不太感興趣...
int x = 10;
int func() {
int y; // REG4
printf("%d\n", x); // Set REG3 = memory(x) and display x
x += 2; // Add 2 to REG3
y = x * x; // REG4 = REG3 * REG3
printf("%d %d\n", x, y); // Do printf(..., REG3, REG4)
x += 5; // REG3 = REG3 + 5
// memory(x) = REG3 (save register to memory)
return y; // return REG4
}
應顯示10, 12, 144
。 為了提高效率(內存訪問比寄存器訪問更昂貴),編譯器會將x的值存儲在內部CPU寄存器(REG3)中,並在func中安全地使用它直到它存儲x的新值(它的結尾)全局var)到x內存位置。 x最后是17。
但是想象一下程序比這更復雜,每分鍾都有一個時鍾中斷,減去10到x 。 如果中斷會發生什么......
void inter_call_by_timer_every_minute() {
x -= 10;
}
...發生在func之后,就在printf("%d\\n", x);
線? func在REG3(10)中有x ,加2(12)並最后加5(17)並將REG3結果存儲到x存儲位置(17)。 這是錯誤的,因為編譯器優化已經隱藏了中斷效果(-10),因為它在最后將值從REG3存儲到存儲器(x),而忽略了由中斷完成的減法 。 正確的結果是: x最初是10,在func中的第一個printf
之后中斷減去10(0),然后添加2,然后是5.結果7。
添加揮發性
volatile int x = 10;
將讓編譯器避免在func中進行x優化
int func() {
int y; // REG4
printf("%d\n", x); // display memory(x)
x += 2; // memory(x) += 2
y = x * x; // REG4 = memory(x) * memory(x)
printf("%d %d\n", x, y); // Do printf(..., memory(x), REG4)
x += 5; // memory(x) += 5
return y; // return REG4
}
並始終從內存中讀取x的值。 在第一個printf之后, inter_call_by_timer_every_minute中斷的結果是x == 7。
我會通過關鍵字解釋我所知道的方式。 extern
表示變量被定義為在定義范圍之外的某處使用。 例如,它可以在頭文件中定義並在.c文件中使用。
volatile
意味着該變量的修改應與外部世界保持一致。 這意味着應該將所有更新提交到主內存,以便共享相同執行空間的其他線程可以看到它。
extern
關鍵字用於聲明一個在其他地方定義的全局變量(這意味着它在其他.c
文件中定義)。
例如,在項目中考慮兩個.c
文件ac
和bc
。 因為全局變量是在ac
定義的,並且該變量可以在該文件中定義的所有函數中訪問。 如果我們想在第二個文件bc
訪問同一個全局變量,那么該變量應該在bc
聲明為extern
ac
文件如下
int flag = 0;
int main()
{
.......
func1();
printf("\nflag value is %d\n", flag).
.......
}
bc
文件如下
extern int flag;
void func1();
{
.....
flag = 10;
.....
}
volatile
關鍵字用於通知編譯器在生成可執行指令時避免進行任何類型的優化。
int flag = 0;
int main()
{
while(flag == 0);
printf("\nflag value is %d\n", flag);
return 0;
}
考慮上面的程序,所有編譯器都會優化while(flag == 0);
while(1);
。 因為在代碼中, while
循環之前沒有where flag
值被更新。 因此,如果該變量值被其他硬件更新,那么它將永遠不會反映在程序執行中。 因此,如果我們將變量聲明為下面的volatile
,編譯器將不會對該變量執行任何優化,並且該程序的行為將如預期的那樣。
volatile int flag = 0;
但是如果沒有辦法讓程序變量的值被其他硬件更新,那么就不需要將該變量聲明為volatile
。 因為對於valatile變量,CPU需要對訪問該變量的每個指令執行I / O操作。 對於一個永遠不會被其他硬件更新的變量,需要考慮這種性能影響。
Extern意味着它在別處定義 - 可能在頭文件中。 易失性是編譯器的信息,它不應該嘗試優化它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.