2012-01-31 70 views
2

我正在使用UnitTest ++框架在我負責的一些C代碼上實現單元測試。最終產品被嵌入並使用const結構來保存配置信息。由於目標主機可以異步修改配置,因此結構的成員都是易失性的。一些結構也被聲明爲不穩定。Volatile關鍵字允許訪問UnitTest ++中的const結構

當我使用const_cast嘗試修改缺少UnitTest Windows 7主機上的volatile關鍵字的結構實例時,出現了分段錯誤。這對我有意義。但是,如果使用volatile關鍵字聲明結構實例,則測試通過。這對我沒有意義。

下面是一個快速代碼示例,顯示了Win7上的gcc問題。切換定義值會導致segfault出現或不出現,具體取決於是否使用了結構的易失性實例。

typedef struct 
{ 
    volatile int foo; 
    volatile int bar; 
} TestStruct; 

const TestStruct constStruct = { 1, 2}; 
volatile const TestStruct volatileConstStruct = { 3, 4}; 

#define SEG_FAULT 0 

int main(void) 
{ 
    TestStruct * constPtr = const_cast<TestStruct*>(&constStruct); 
    TestStruct * constVolPtr = const_cast<TestStruct*>(&volatileConstStruct); 

    #if(SEG_FAULT == 0) 
     constVolPtr->foo = 10; 
    #else 
     constPtr->foo = 20; 
    #endif 
} 

任何人都可以幫助我理解爲什麼volatile關鍵字提供了segfault的解決方法嗎?另外,任何人都可以提出一種方法,允許我修改單元測試的結構中的值,而無需將volatile關鍵字添加到所有結構實例中?

編輯:

我剛剛發現,你可以在C這樣做:

#define const 

包括有效「常量取消定義」在上面的測試夾具允許我的目標編譯器看const關鍵字並將結構正確放置到閃存中。然而,UnitTest ++編譯器的預處理器去除了const關鍵字,所以我的測試夾具能夠修改結構。

該解決方案的缺點是我不能添加驗證函數調用的正確const操作的單元測試。但是,由於從結構實例中刪除const不是一個選項(需要將數據放在閃存中),這似乎是我必須忍受的一個缺點。

+0

您正在代碼級別混合使用C和C++,而不僅僅是在接口級別上,可能是一個壞主意。這是兩種不同的語言。特別是他們關於什麼是常量的概念和什麼是const限定對象有所不同。 – 2012-01-31 22:08:11

+0

我正在使用需要C++模塊的UnitTest ++來測試C代碼。爲了示例的目的,我將所有混合的C/C++放入同一個文件中(我無法分享正在處理的實際代碼)。在我的環境中,沒有混合的C/C++。 – Egat 2012-01-31 23:25:13

回答

0

我相信標準中的腳註會給你答案。 (請注意,腳註不是標準化的。)

在標準N1570草案§6.7.3:

132)的執行可以將一個const對象,它是不揮發 在只讀區域的存儲。

這意味着將具有volatile關鍵字定義的結構將被放置在讀寫存儲器,儘管,它的定義const的事實。

有人可能會說編譯器不允許將任何結構放在只讀存儲器中,因爲它們都包含易失性成員。如果我是你,我會發送一個編譯器錯誤報告。

任何人都可以幫助我理解爲什麼volatile關鍵字爲segfault提供了一個 解決方法?另外,任何人都可以建議一種方法,以 允許我修改結構中的值單元測試沒有 添加volatile關鍵字到所有的結構實例?

你不行。 A const對象被放置在只讀存儲器中,如果您寫入,則會觸發段錯誤。請刪除const或添加volatile - 我強烈建議您刪除const

+0

我的理解是const只是禁止代碼直接修改數據。由於我正在開發一個micro,所以const用於告訴編譯器將數據放入flash中。它可以被修改,但不能通過直接訪問。 – Egat 2012-01-31 21:17:13

4

爲什麼這種奇怪的行爲?
使用const_cast修改const對象是未定義的行爲
const_cast用於指定非const對象的const指針,並且您想將指針指向它。

爲什麼它可以與volatile一起使用?
不確定。然而,它仍然是一個未定義的行爲,你只是幸運的。

未定義行爲的問題是所有安全投注都關閉,程序可能會顯示任何行爲。它可能似乎工作或可能無法正常工作。可能會崩潰或顯示任何奇怪的行爲。
最好不要寫任何代碼表現未定義的行爲,這樣可以節省對這種情況的保證解釋。

如何解決這個問題?
請勿將您修改的對象聲明爲const,由於您打算在程序/測試過程中修改它們,因此它們不應該是const。目前,您正在向編譯器做出承諾,即您的結構對象是不可變的(const),但稍後您會通過修改它來破壞該合同。只有保留它才能做出承諾。

+1

我寧願說「'const_cast'用於獲取一個非const指針指向一個const對象」,因爲這是典型的用例。 (例如,認爲用於C++的'strchr'。) – 2012-01-31 19:38:35

+0

C++有'strchr'的const超載來避免這種情況。 – 2012-01-31 20:31:18

+0

謝謝,我沒有意識到這是未定義的行爲。如下所述,我正在使用嵌入式處理器。使用const關鍵字將結構放入Flash中。我只需要修改它來配置存儲在結構中的模塊參數以設置單元測試。我必須找出另一種解決方法,因爲我不想依賴易失性關鍵字將未定義的行爲推向可寫內存。 – Egat 2012-01-31 21:17:26