volatile struct = struct不可能,为什么?

mak*_*kum 23 c++ struct volatile

struct FOO{
    int a;
    int b;
    int c;
};

volatile struct FOO foo;

int main(void)
{
    foo.a = 10;
    foo.b = 10;
    foo.c = 10;
    struct FOO test = foo;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这将无法编译,因为 struct FOO test = foo; 生成错误:

错误:'const FOO&'类型的绑定引用到'volatile FOO'会丢弃限定符

如何在C++中复制volatile struct到另一个struct(在C++ 11之前)?

许多人建议只删除volatile,但在这种情况下我不能这样做,因为我想在μC内复制当前的SPI-Reg设置,并且这被制造商标题声明为volatile.我想复制这些设置,因为制造商还提供了一个库来使用SPI进行EnDat-Communication,而我无法访问源代码.由于我必须在运行期间更改SPI-Reg-Settings,因此我希望能够轻松返回到库SPI设置,而无需再次调用init_endat() - lib fkt(如果我将其调用两次,则未指定会发生什么).

我可以使用memcopy()吗?

如上所述,这是以下问题的副本.

为什么我没有从volatile中提供默认的复制构造函数?

YSC*_*YSC 23

这是错误的,因为FOO有一个隐式复制构造函数定义为:

FOO(FOO const&);
Run Code Online (Sandbox Code Playgroud)

FOO test = foo;foo类型写volatile FOO,调用:

FOO(volatile FOO const&);
Run Code Online (Sandbox Code Playgroud)

但是对引用到非易失性隐式转换的引用 - 易失性是不正确的.

从这里出现两种解决方案:

  1. 不要使易失性转换为非易失性转换;
  2. 定义一个合适的拷贝构造函数或"手动"复制对象成员;
  3. const_cast 可以删除volatile限定符,但这是未定义的行为,如果你的底层对象是有效的volatile.

我可以使用memcopy()吗?

不,你不能,memcpy与volatile对象不兼容:thre不会引起指针到易失性的重载,没有调用未定义的行为就没有什么可以做的.

所以,作为一个结论,如果你不能添加一个构造函数,你最好的镜头FOO是定义:

FOO FOO_copy(FOO volatile const& other)
{
    FOO result;
    result.a = other.a;
    result.b = other.b;
    result.c = other.c;
    return result;
}
Run Code Online (Sandbox Code Playgroud)

或者使用C++ 11 std::tie:

FOO FOO_copy(FOO volatile const& other)
{
    FOO result;
    std::tie(result.a, result.b, result.c) = std::tie(other.a, other.b, other.c);
    return result;
}
Run Code Online (Sandbox Code Playgroud)

  • @JiveDadson它有点包含在1.;)但是,在我们不知道的情况下,OP的上下文中可能真的需要`volatile`.但是我们从[OP的个人资料页面](/sf/users/648385601/)知道他们是一个_embedded_软件工程师,所以...... (10认同)

小智 19

为了给出答案的另一种方法,解决为什么这没有意义,而不仅仅是C++标准认为这是无效的:

最重要的volatile是,您可以精确控制何时访问哪个变量.这意味着给予volatile int i, j;,i = 1; j = 2;j = 2; i = 1;不是做同样的事情.编译器无法自由地将一个转换为另一个.这同样适用于读取:给定volatile int i, j; int x, y;,x = i; y = j;并且y = j; x = i;不做同样的事情.的存在volatile意味着访问必须在发生正是您指定的顺序.

现在,在你的例子中,该怎么struct FOO test = foo;办?你从来没有说明你是想先读foo.a,然后foo.b,最后foo.c,或者先读foo.c,然后foo.b,最后foo.a,或者也许是其他一些订单.

如果您愿意,您可以这样做:

struct FOO test;
test.a = foo.a;
test.b = foo.b;
test.c = foo.c;
Run Code Online (Sandbox Code Playgroud)

在这里,您明确指定了对foo字段的访问顺序,以避免出现此问题.

  • 对于一些开发人员来说,我喜欢`volatile`是如此神秘的一样:) @JAB你知道如何允许编译器按照"as-if"规则重新排序指令吗?那么这个规则不适用于volatile对象(参见上面引用的`[intro.execution]/8.1`).你所谈论的是与多线程程序有关,是的,在这种情况下,`volatile`没有帮助.hvd的答案是关于线程内指令. (11认同)
  • @JiveDadson你在阅读的内容比我实际写的更多.我写的*是*volatile的意思.Per [intro.execution] p8.1:"严格按照抽象机器的规则评估对volatile对象的访问." (5认同)
  • 这不是"易变"的意思.这就是std :: atomic与内存顺序std :: memory_order_seq_cst的意思.Visual C++为volatile提供了一些内存顺序保证,除非您设置了标准合规性标志,但承诺并不那么强大.`volatile`仅用于访问内存映射硬件,我猜UNIX信号处理程序. (4认同)