繁体   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