2014-05-19 20 views
1

注:鑄造揮發性表達式的結果作廢

這是不是已經被問了很多次同樣的事情。是的,我已經閱讀了很多關於無效的帖子。這些問題都沒有導致答案,我懷疑在這裏是正確的。


背景信息:

嵌入式C.這具體涉及存儲器映射的揮發性指針。換句話說,外設寄存器。

我碰到下面一行在涉及寫入一個I2C外圍例行傳來:

(void) I2C1->SR2; 

I2C1已經#defined爲結構*易失性存儲器。

所以這一行的結果並不是「避免編譯器警告」,因爲這是我在這裏所做的所有搜索的答案。它實際上會導致編譯器讀取該寄存器(因爲它是易失性的),然後將其丟棄。該寄存器中有標誌。閱讀寄存器的行爲會導致標誌清除。

現在這是非常重要的,因爲目標是清除標誌,不僅避免一些編譯器警告!

但是我擔心的是,在某種程度的優化或者不同的編譯器中,這些代碼會被優化掉。這是我的問題:

這會得到優化,或有沒有辦法保證它不會被優化呢?

我把所有的相關的代碼下面一起:

#define PERIPH_BASE   ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region        */ 
#define APB1PERIPH_BASE  PERIPH_BASE 
#define I2C1_BASE    (APB1PERIPH_BASE + 0x5400) 
#define I2C1    ((I2C_TypeDef *) I2C1_BASE) 
typedef struct 
{ 
    __IO uint16_t CR1;  /*!< I2C Control register 1,  Address offset: 0x00 */ 
    uint16_t  RESERVED0; /*!< Reserved, 0x02         */ 
    __IO uint16_t CR2;  /*!< I2C Control register 2,  Address offset: 0x04 */ 
    uint16_t  RESERVED1; /*!< Reserved, 0x06         */ 
    __IO uint16_t OAR1;  /*!< I2C Own address register 1, Address offset: 0x08 */ 
    uint16_t  RESERVED2; /*!< Reserved, 0x0A         */ 
    __IO uint16_t OAR2;  /*!< I2C Own address register 2, Address offset: 0x0C */ 
    uint16_t  RESERVED3; /*!< Reserved, 0x0E         */ 
    __IO uint16_t DR;   /*!< I2C Data register,   Address offset: 0x10 */ 
    uint16_t  RESERVED4; /*!< Reserved, 0x12         */ 
    __IO uint16_t SR1;  /*!< I2C Status register 1,  Address offset: 0x14 */ 
    uint16_t  RESERVED5; /*!< Reserved, 0x16         */ 
    __IO uint16_t SR2;  /*!< I2C Status register 2,  Address offset: 0x18 */ 
    uint16_t  RESERVED6; /*!< Reserved, 0x1A         */ 
    __IO uint16_t CCR;  /*!< I2C Clock control register, Address offset: 0x1C */ 
    uint16_t  RESERVED7; /*!< Reserved, 0x1E         */ 
    __IO uint16_t TRISE;  /*!< I2C TRISE register,   Address offset: 0x20 */ 
    uint16_t  RESERVED8; /*!< Reserved, 0x22         */ 
    __IO uint16_t FLTR;  /*!< I2C FLTR register,   Address offset: 0x24 */ 
    uint16_t  RESERVED9; /*!< Reserved, 0x26         */ 
} I2C_TypeDef; 

某處的功能....

(void) I2C1->SR2; 

預先感謝任何幫助。這個網站對於像我這樣的新手來說是一個很好的資源。

+0

請注意,如果沒有編譯器和處理器的製造商/型號,「答案」對您而言可能是正確的。 – KevinDTimm

+0

其實這是我猜這個問題的答案。如果它依賴於編譯器,那麼這是錯誤的做法。所以同樣的問題略有不同:「是否有獨立於編譯器的方法來實現相同的目標?」順便說一下編譯器是GCC。 – user1160866

+1

如果訪問易失性對象,那麼不能通過符合的C編譯器優化該訪問。 –

回答

2

volatile關鍵字是便攜式方式,以防止內存訪問被優化和/或重新排序。應該注意的是,正確使用volatile關鍵字使得將表達式的結果轉換爲(void)是不必要的。例如,假設我已經鍵入了一個結構並擁有該結構的一個實例。

typedef struct 
{ 
    int a; 
    int b; 
} 
    SomeStruct; 

SomeStruct test; 

下面的代碼將導致編譯器抱怨「警告:表達結果未使用」

SomeStruct *vptr = &test; 
    vptr->a; 

我可以由結果鑄造(void)避免該警告,但隨後的編譯器可以自由地優化閱讀。

SomeStruct *vptr = &test; 
    (void) vptr->a; 

但是,如果我宣佈指針volatile,不投給(void),我不會得到一個警告,編譯器將優化掉讀取。

volatile SomeStruct *vptr = &test; 
    vptr->a; 

這個故事的寓意是,如果你使用的是volatile關鍵字,你應該投表達式(void)。這隻會抑制警告,否則將會標識關鍵字volatile丟失或不正確的使用。

+0

我想補充說明一下。 – user1160866

+0

我想補充說明一下。它可能並不明顯,但在代碼片斷中,它上面的「__IO」是「volatile」的縮寫。另外,我只編譯了「I2C1-> SR2」,但沒有強制轉換,並且使用最高優化設置,並且仍然可以正確生成讀取。所以謝謝user3386109。我對此表示滿意。好極了! – user1160866

+0

啊,很高興聽到:) – user3386109