簡體   English   中英

易失的結構與類型轉換

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM