【问题标题】:passing argument 2 of 'memcpy' discards 'volatile' qualifier from pointer target type传递“memcpy”的参数 2 从指针目标类型中丢弃“volatile”限定符
【发布时间】:2016-08-12 06:32:12
【问题描述】:

我有一个 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
);

我收到此警告:

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

阅读这些部分是一种更安全的方式,还是使用 memcpy 并防止出现此警告的更好方式?

【问题讨论】:

  • result_len 的典型值是多少?寄存器都是 8 位的,寄存器之间没有间隙吗?就个人而言,在处理硬件寄存器时,使用memcpy 不是我的首选。但是如果没有关于硬件的更多信息,就很难回答您的问题。
  • 检查:您想一次读取多个寄存器吗?
  • 如何同步此内存以避免竞争条件?如果你确定它是同步的,为什么不直接扔掉 volatile 修饰符呢?
  • 在大多数情况下你真的不想使用volatile。标准严重低估了它,它并没有使事情变得线程安全(尽管许多人似乎相信这一点),它主要只是用来阻止优化器对你的代码做聪明的事情。你确定你真的不想要一个原子变量吗?
  • @JesperJuhl:这是一个嵌入式项目,标准中存在公认的缺陷,幸运的是,任何实现都没有实现该缺陷。相反,他们实现了应有的方式。对于硬件寄存器,volatile 是正确的限定符。

标签: c embedded


【解决方案1】:

memcpy 与 volatile 对象不兼容,函数签名中不匹配的指针类型有助于向您指出这一点。 memcpy 可以以任何顺序、任何单位大小进行复制、多次读取源的部分、多次写入目标的部分等。另一方面,volatile 表示访问的顺序和次数的意图对象必须与抽象机器中的对象完全相同。如果要复制volatile 数组,则需要编写自己的复制循环,看起来像一个幼稚的memcpy,并为循环中的指针使用正确的volatile 类型。

【讨论】:

  • @jforberg 取决于每种情况下的损坏数据。您可能不关心读取时数据的变化,但要关心每个寄存器只读取一次。取决于硬件实现和寄存器的含义。
  • @jforberg:竞争条件超出了问题的范围。一个 volatile 对象被允许(并且会,对于各种硬件)在你每次阅读它时产生不同的结果/行为;这是实现定义的。但这不是你不能使用 memcpy 的原因。
  • @atturri 好的,这更有意义。看来我确实误读了这个问题。我在 glibc 的源代码中看到,如果操作系统支持它,它有时实际上可以复制整个 VM 页面。如果 VM 页面引用内存映射硬件,这可能不会很好地工作。
  • @jforberg:问题是关于硬件外围寄存器的。这与 CPU 的并发代码执行完全不同。例如,这些区域通常是严格有序的/不可缓存的。
  • @Hani_l:这只有在 MMIO 寄存器或任何底层 volatile 对象可以安全地以字节形式访问时才有效(但在这种情况下,它通常应该可以工作)。我使用过字节 IO 不执行任何操作或行为异常严重的硬件,并且需要 32 位字 IO 才能正常工作。因此,您确实需要编写一个适合您访问的任何内容的函数。
【解决方案2】:

一般建议不要将memcpy 用于硬件外围寄存器或volatile 一般合格对象,即使iff它们占用无间隙的内存区域。他们通常需要特定的访问模式,memcpy 不保证。这包括使用优化的更广泛的传输、多次访问同一位置或更改访问顺序。

出于上述和以下原因,甚至不要考虑抛弃volatile 限定符!编译器可能会很好地优化调用(例如,如果您有两个相同的调用,而中间没有更改源区域或目标区域),则组合两个访问或在其他硬件访问之前/之后移动调用。

改为编写您自己的复制函数/循环来保留限定符。这将迫使编译器生成完全符合您要求的代码。请记住为复制指针使用正确的类型。另请注意,标准整数类型对于特定大小的硬件寄存器不是一个好的选择。请改用stdint.h 中的固定宽度类型,例如uint8_tuint16_t、...。

【讨论】:

  • "如果将同一个源复制到同一个目标" memcpy 不允许这样做,参数是restrict 指针。为此,您必须使用 memmove
  • @Lundin:抱歉,措辞不好。我希望编辑更清楚我的真正意思。
【解决方案3】:

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

【讨论】:

  • 它全部用 C 编写(C++ 标签是由堆栈溢出建议添加的,我什至不确定何时!)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-02
  • 1970-01-01
  • 2011-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-29
相关资源
最近更新 更多