【问题标题】:C string standard library, memset and discarded volatile keyword [duplicate]C字符串标准库,memset和丢弃的volatile关键字[重复]
【发布时间】:2021-01-20 16:45:22
【问题描述】:

我在 xc32 编译器(基于 gcc 的微控制器编译器,不是开源的)上收到这样的警告。

modem_uart.c:66:5:警告:传递 'memset' 丢弃的参数 1 来自指针目标类型的 'volatile' 限定符 [默认启用]

代码如下:

#include <string.h>
// (...)
volatile char rxbuf[MODEM_UART_RXBUF_SIZE];
// (...)

void some_function(void)
{    
    // (...)
    memset(rxbuf, 0, MODEM_UART_RXBUF_SIZE); // <- warning here
    // (...)
}

有人能解释一下为什么编译器会丢弃 volatile 吗?

【问题讨论】:

  • 因为memset() 的声明在第一个参数上没有volatile
  • 库函数没有丢弃volatile,此代码尝试通过调用丢弃volatile,编译器会明智地发出警告。
  • @FredLarson 是的,实际上这与我正在做的非常相似。感谢您提供的链接也解释了我的其他顾虑。

标签: c volatile xc32


【解决方案1】:

memset标准中的规范有如下声明:

void *memset(void *s, int c, size_t n);

第一个参数没有声明为volatile void *s。所以它不能保证遵守访问volatile 数据的额外限制。对memset() 的每次调用都将目标视为易失性,这会对性能造成不必要的影响。

如果您需要这些保证,则应将 memset() 调用替换为显式循环。

for (int i = 0; i < MODEM_UART_RXBUF_SIZE; i++) {
    rxbuf[i] = 0;
}

如果您在代码中的多个位置都需要它,可以将其放入 volatile_memset() 函数中。

【讨论】:

  • 我可以在for 中为i 添加register 修饰符以使其更快吗?好吧,这可能是另一个问题的主题......
  • 这几乎不需要。编译器擅长找出哪些变量可以从寄存器中获得最大收益。
  • @Kamil 如果它是最快的选项,怎么能强迫编译器做一些它已经可以做的事情可能让你的代码更快?
  • @Kamil 一般来说,register 修饰符被认为是过时的。几年前,当优化器不像现在这样聪明时,它很有用。
  • @Barmar 嗯,这是微控制器编译器,我不知道它基于哪个 gcc 版本,可能有自定义优化器代码(不是人群编写的,可能 Microchip 中很少有人编写)。 ..也许我会在反汇编窗口中检查它。
【解决方案2】:

您的平台不提供保证尊重它为volatile 提供的任何保证的memset 函数。因此,为了调用memset,编译器必须丢弃rxbuf 上的volatile 限定符。

您可能应该编写自己的memset 实现,尊重您期望volatile 为您提供的任何保证。 This answer 包含一个 memcpy 以解决类似问题。如果没有这样的保证,那就去掉volatile

【讨论】:

    猜你喜欢
    • 2016-05-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-14
    • 1970-01-01
    • 2015-06-03
    • 2011-04-05
    • 1970-01-01
    相关资源
    最近更新 更多