简体   繁体   English

易失的结构与类型转换

[英]volatile struct vs. typecast

I have the following declarations in my code: 我的代码中包含以下声明:

h file: h文件:

typedef struct {
    bool qualified : 1;
    bool running : 1;
} calibration_state_t;

calibration_state_t get_calibration_state();

cpp file: cpp文件:

volatile calibration_state_t calibration_state = {false ,false};

The function 功能

calibration_state_t get_calibration_state() {
    return *(calibration_state_t *)&calibration_state;
}

compiles. 编译。 However if I replace the return statement with 但是,如果我将return语句替换为

return (calibration_state_t)calibration_state;

It fails with 它失败了

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&)

The compiler is avr-gcc but I suspect this does not matter. 编译器是avr-gcc,但我怀疑这没有关系。 Why does the compiler fail to compile the type cast? 为何编译器无法编译类型转换? How would I get to the desired return value in a clean way? 我如何以一种干净的方式达到期望的返回值?

Your code that uses a cast has undefined behavior (§7.1.6.1 [dcl.type.cv]/p6): 您使用强制类型转换的代码具有未定义的行为(§7.1.6.1[dcl.type.cv] / p6):

If an attempt is made to refer to an object defined with a volatile-qualified type through the use of a glvalue with a non-volatile-qualified type, the program behavior is undefined. 如果试图通过使用具有非挥发限定类型的glvalue来引用以挥发限定类型定义的对象,则程序行为是不确定的。

*(calibration_state_t *)&calibration_state is a glvalue of type calibration_state_t , a non-volatile-qualified type, and is being used to refer to calibration_state , an object defined with a volatile-qualified type. *(calibration_state_t *)&calibration_state是非定性类型的calibration_state_t类型的glvalue,用于引用calibration_state ,该对象是用非定性类型定义的对象。 Undefined behavior results. 未定义的行为结果。

Relying on undefined behavior to get the semantics you want is incredibly dangerous. 依靠未定义的行为来获取所需的语义是非常危险的。 While the compiler is unlikely to actually conjure nasal demons or blow your legs off (though it is allowed to), an optimizing compiler may legally assume from the undefined behavior that get_calibration_state will never be called, and that any code path containing it is unreachable, and generate code accordingly. 尽管编译器不太可能实际产生鼻恶魔或get_calibration_state (尽管允许这样做),但优化的编译器可能会根据未定义的行为合法地假定永远不会调用get_calibration_state ,并且包含该代码的任何代码路径均无法访问,并据此生成代码。 This kind of optimizations depending on undefined behavior can and do happen. 这种根据未定义行为的优化可以并且确实会发生。

In reference binding, volatile is like const - you can't bind a const object to a non- const reference, and you can't bind a volatile object to a non- volatile reference. 在引用绑定中, volatile就像const一样-您不能将const对象绑定到非const引用,也不能将volatile对象绑定到非易失volatile引用。 Give your class a copy constructor that takes a const volatile & . 给您的类一个采用const volatile &的复制构造const volatile &

What is the desired behavior exactly? 期望的行为到底是什么? Must ordering be preserved, for example? 例如,必须保留订购吗? If something else sets qualified and then running , is it okay to get the old value of qualified but the new value of running ? 如果还有其他条件设置qualified然后running ,是否可以获取qualified的旧值但获得新的running值?

Because the structure is volatile, operations on it are part of the visible behavior of the program. 由于结构是易失性的,因此对其进行的操作是程序可见行为的一部分。 That is, this: 也就是说,这是:

calibration_state_t get_calibration_state()
{
    calibration_state_t ret;
    ret.qualified = calibration_state.qualified;
    ret.running = calibration_state.running;
    return ret;
}

Is not the same as: 与以下内容不同:

calibration_state_t get_calibration_state()
{
    calibration_state_t ret;
    ret.running = calibration_state.running;
    ret.qualified = calibration_state.qualified;
    return ret;
}

So, you have to code what you want. 因此,您必须编写所需的代码。 How can the compiler know what behavior you want? 编译器如何知道您想要什么行为? You got some behavior by lying to the compiler, but I doubt it's the behavior you want. 您对编译器撒谎有一些行为,但是我怀疑这是您想要的行为。

For me it looks that: 对我来说,看起来:

return *(calibration_state_t *)&calibration_state;

explicitly removes the volatile specifier, so the implicitly defined copy constructor: 显式删除volatile说明符,因此隐式定义的副本构造函数:

calibration_state_t(const calibration_state_t&)

is executed. 被执行。

When you don't cast the calibration_state instance first, then compiler can not call the copy constructor ( volatile remains). 当您不首先强制转换calibration_state实例时,编译器将无法调用复制构造函数( volatile仍然存在)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM