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