[英]volatile struct vs. typecast
我的代碼中包含以下聲明:
h文件:
typedef struct {
bool qualified : 1;
bool running : 1;
} calibration_state_t;
calibration_state_t get_calibration_state();
cpp文件:
volatile calibration_state_t calibration_state = {false ,false};
功能
calibration_state_t get_calibration_state() {
return *(calibration_state_t *)&calibration_state;
}
編譯。 但是,如果我將return語句替換為
return (calibration_state_t)calibration_state;
它失敗了
dcf77.cpp: In function ‘DCF77_Frequency_Control::calibration_state_t DCF77_Frequency_Control::get_calibration_state()’:
dcf77.cpp:2923:37: error: no matching function for call to ‘DCF77_Frequency_Control::calibration_state_t::calibration_state_t(volatile DCF77_Frequency_Control::calibration_state_t&)’
dcf77.h:204:7: note: candidates are: DCF77_Frequency_Control::calibration_state_t::calibration_state_t()
dcf77.h:204:7: note: DCF77_Frequency_Control::calibration_state_t::calibration_state_t(const DCF77_Frequency_Control::calibration_state_t&)
編譯器是avr-gcc,但我懷疑這沒有關系。 為何編譯器無法編譯類型轉換? 我如何以一種干凈的方式達到期望的返回值?
您使用強制類型轉換的代碼具有未定義的行為(§7.1.6.1[dcl.type.cv] / p6):
如果試圖通過使用具有非揮發限定類型的glvalue來引用以揮發限定類型定義的對象,則程序行為是不確定的。
*(calibration_state_t *)&calibration_state
是非定性類型的calibration_state_t
類型的glvalue,用於引用calibration_state
,該對象是用非定性類型定義的對象。 未定義的行為結果。
依靠未定義的行為來獲取所需的語義是非常危險的。 盡管編譯器不太可能實際產生鼻惡魔或get_calibration_state
(盡管允許這樣做),但優化的編譯器可能會根據未定義的行為合法地假定永遠不會調用get_calibration_state
,並且包含該代碼的任何代碼路徑均無法訪問,並據此生成代碼。 這種根據未定義行為的優化可以並且確實會發生。
在引用綁定中, volatile
就像const
一樣-您不能將const
對象綁定到非const
引用,也不能將volatile
對象綁定到非易失volatile
引用。 給您的類一個采用const volatile &
的復制構造const volatile &
。
期望的行為到底是什么? 例如,必須保留訂購嗎? 如果還有其他條件設置qualified
然后running
,是否可以獲取qualified
的舊值但獲得新的running
值?
由於結構是易失性的,因此對其進行的操作是程序可見行為的一部分。 也就是說,這是:
calibration_state_t get_calibration_state()
{
calibration_state_t ret;
ret.qualified = calibration_state.qualified;
ret.running = calibration_state.running;
return ret;
}
與以下內容不同:
calibration_state_t get_calibration_state()
{
calibration_state_t ret;
ret.running = calibration_state.running;
ret.qualified = calibration_state.qualified;
return ret;
}
因此,您必須編寫所需的代碼。 編譯器如何知道您想要什么行為? 您對編譯器撒謊有一些行為,但是我懷疑這是您想要的行為。
對我來說,看起來:
return *(calibration_state_t *)&calibration_state;
顯式刪除volatile
說明符,因此隱式定義的副本構造函數:
calibration_state_t(const calibration_state_t&)
被執行。
當您不首先強制轉換calibration_state
實例時,編譯器將無法調用復制構造函數( volatile
仍然存在)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.