传递'memcpy'的参数2从指针目标类型中丢弃'volatile'限定符

Han*_*i_l 12 c embedded

我有一个volatile char * start_address;指向寄存器部分(可能由于硬件行为而改变).我需要阅读它,我正在使用:

memcpy (
    result_p,            // starting address of destination
    start_address,       // starting address of source
    result_len           // for the length of the payload
);
Run Code Online (Sandbox Code Playgroud)

我收到这个警告:

从指针目标类型传递' memcpy'discards' volatile'限定符的参数2

是一种更安全的方式阅读部分或更好的方式来使用memcpy并防止这种警告?

R..*_*R.. 13

memcpy与volatile对象不兼容,函数签名中不匹配的指针类型有助于指出这一点.memcpy可以以任何顺序复制,以任何单位大小,多次读取源的部分,多次写入目的地的部分,等等.另一方面,volatile表达了对对象的序列和访问次数必须准确的意图他们将在抽象机器中做什么.如果要复制volatile数组,则需要编写自己看起来像天真的复制循环memcpy,并volatile在循环中使用正确的类型作为指针.

  • @jforberg:竞赛条件超出了问题的范围.允许一个易失性对象(并且对于各种硬件)每次读取时都会产生不同的结果/行为; 这是实现定义的.但这不是你不能使用`memcpy`的原因. (3认同)
  • @jforberg 取决于每种情况下损坏的数据。您可能不关心读取时数据的变化,但请注意每个寄存器被读取一次且仅一次。取决于硬件实现和寄存器的含义。 (2认同)

too*_*ite 7

一般的建议是不使用memcpy的硬件外设寄存器或volatile一般合格的对象,甚至当且仅当它们占据间隙更少的内存区域.他们通常需要特定的访问模式memcpy并不能保证.这包括使用优化的更宽传输,多次访问相同位置或更改访问顺序.

由于上述原因和以下原因,甚至不要考虑丢掉volatile限定符!编译器可以很好地优化呼叫(例如,如果您有两个相同的呼叫而不更改源和目​​标区域之间),组合两个访问或在其他硬件访问之前/之后移动呼叫.

而是编写自己的复制函数/循环来保持限定符.这将迫使编译器生成完全符合您需要的代码.请记住为复制指针使用正确的类型.另请注意,标准整数类型不是特定大小的硬件寄存器的理想选择.从使用固定宽度类型stdint.h一样uint8_t,uint16_t...来代替.

  • “如果您将相同的源复制到相同的目标”,则memcpy不允许,该参数是`restrict`指针。为此,您必须使用`memmove`。 (2认同)

MSa*_*ers 6

在 C++ 中,您可以使用std::copy. 它将采用任何类型的(输入)迭代器,并且指向的指针 volatile是完全有效的输入迭代器。