2017-10-10 84 views
1

假設我有下面的C代碼:C:使用靜態揮發與「吸氣」功能和中斷

/* clock.c */ 

#include "clock.h" 

static volatile uint32_t clock_ticks; 

uint32_t get_clock_ticks(void) 
{ 
    return clock_ticks; 
} 

void clock_tick(void) 
{ 
    clock_ticks++; 
} 

現在我打電話clock_tick(即:增加clock_ticks變量)的中斷內,而從打電話get_clock_ticks()main()功能(即:在中斷之外)。

我的理解是,clock_ticks應被聲明爲volatile,因爲否則編譯器可以優化其接入,並main()覺得值沒有改變(雖然它實際上是從中斷的更改)。

不知使用get_clock_ticks(void)功能那裏,而不是訪問變量直接形成main()(即:不聲明爲static)實際上可以強制編譯器從存儲器加載變量,即使它沒有被聲明爲揮發性的。

我想知道有人告訴我這可能會發生。這是真的嗎?在哪些條件下?無論如何,如果我使用「吸氣」功能,我應該總是使用volatile嗎?

+0

您的案例中的'volatile'是必不可少的。當從中斷訪問變量時它正在發揮作用。這樣編譯器就知道有一些東西在訪問和修改它不知道的變量。否則,你的「getter」將(可能)返回一個常量,變量的初始值。 –

+0

https://stackoverflow.com/questions/5822386/the-volatile-keyword-in-c-language –

+0

getter函數可能會被內聯。可能存在緩存一致性問題,這些問題可能表現爲非確定性行爲。 – jxh

回答

2

對於使用volatile而言,吸氣功能對此沒有任何幫助。

  • 假設編譯器看到你剛剛取得了上面兩行的值,並且從那以後沒有改變它。
  • 如果這是一個很好的優化編譯器,我希望它看到函數調用沒有副作用,只是簡單地優化了函數調用。

如果get_clock_ticks()external(即在一個單獨的模塊中),事情是不同的(也許這就是你所記得的)。

可以在正常程序流程之外改變其值的東西(例如在ISR中),應該將總是聲明爲volatile

+0

感謝您的回答。等到明天才接受,以防有人想在這裏添加點東西。 ^^ – Peque

+0

顯示的代碼來自'clock.c'文件,幷包含一個頭文件'clock.h'。使用時鐘函數的代碼(例如,包含'main()'的文件)只包含頭文件,並且沒有內聯任何函數的機會。當然,沒有什麼可以阻止OP包含'clock.c'文件,但這不是預期的結果。 (該代碼也沒有顯示如何設置中斷等) –

+0

@JonathanLeffler你認爲我們已經看到了所有的「clock.c」?我不一定這樣做。當'get_clock_ticks()'從外部或內部調用'clock.c'時,優化選項是有區別的(這更糟糕,因爲「不工作」突變爲「有時似乎有效」) – tofro

1

不要忘記,即使您當前編譯聲明get_clock_ticks的代碼和使用它作爲單獨模塊的代碼,也許有一天您會使用鏈接時間或跨模塊優化。即使您正在使用getter函數,也要保持「volatile」 - 在這種情況下,它不會損害代碼生成,並使代碼正確。

你沒有提到的一件事是處理器的位大小。如果它不能在單個操作中讀取32位值,那麼get_clock_ticks()有時會失敗,因爲讀取不是原子的。

+0

謝謝。是的,它是一個32位的ARM。 – Peque