我的代码中有以下声明:
h file:
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,但我怀疑这没关系。为什么编译器无法编译类型转换?如何以干净的方式获得所需的返回值?
答案 0 :(得分:3)
使用强制转换的代码具有未定义的行为(第7.1.6.1节[dcl.type.cv] / p6):
如果尝试引用用a定义的对象 通过使用带glvalue的volatile限定类型 非易失性限定类型,程序行为未定义。
*(calibration_state_t *)&calibration_state
是类型为calibration_state_t
的glvalue,是一种非易失性限定类型,用于引用calibration_state
,这是一个使用volatile限定类型定义的对象。未定义的行为结果。
依靠未定义的行为来获取您想要的语义是非常危险的。虽然编译器实际上不可能实现鼻子恶魔或者断掉你的腿(虽然它被允许),但是优化编译器可以从未定义的行为中合法地假设get_calibration_state
永远不会被调用,并且包含任何代码路径它无法访问,并相应地生成代码。这种取决于未定义行为的优化可能并且确实会发生。
在引用绑定中,volatile
与const
类似 - 您无法将const
对象绑定到非const
引用,并且您无法绑定volatile
反对非volatile
引用。为您的班级提供一个带有const volatile &
。
答案 1 :(得分:2)
究竟是什么样的行为?例如,必须保留订购吗?如果其他内容设置为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;
}
所以,你必须编写你想要的代码。编译器如何知道您想要的行为?通过向编译器说谎,你得到了一些行为,但我怀疑它是你想要的行为。
答案 2 :(得分:1)
对我而言,看起来:
return *(calibration_state_t *)&calibration_state;
显式删除volatile
说明符,因此隐式定义的复制构造函数:
calibration_state_t(const calibration_state_t&)
已执行。
如果您没有先放置calibration_state
实例,那么编译器就无法调用复制构造函数(volatile
仍然存在)。