14
volatile char* sevensegment_char_value;

void ss_load_char(volatile char *digits) {
    ...
    int l=strlen(digits);
    ...
 }

 ss_load_char(sevensegment_char_value);

在上面的例子中,我收到了来自 avr-gcc 编译器的警告

Warning 6   passing argument 1 of 'strlen' discards 'volatile' qualifier from pointer target type [enabled by default]

所以我必须以某种方式将值从 volatile 复制到 non-volatile var?什么是安全的解决方法?

4

3 回答 3

11

C 中没有“内置”解决方法之类的东西。Volatile 告诉编译器,变量的内容(或者在你的情况下,变量指向的内存)可以在编译器没有注意到的情况下发生变化并强制编译器直接从数据总线读取数据,而不是使用寄存器中可能存在的副本。因此,volatile 关键字用于避免编译器优化引起的奇怪行为。(如果你愿意,我可以进一步解释)

在您的情况下,您有一个声明为 volatile 的字符缓冲区。如果您的程序在不同的上下文(例如 ISR)中更改此缓冲区的内容,则必须实现某种同步机制(例如禁用特定中断等)以避免数据不一致。获取“锁定”(禁用中断)后,您可以逐字节地将数据复制到本地(非易失性)缓冲区,并在该缓冲区上工作以完成例程的其余部分。

如果缓冲区不会更改您的读取访问上下文的“外部”,我建议省略 volatile 关键字,因为它没有用处。

要判断正确的解决方案,需要更多关于您的确切用例的信息。

于 2012-11-29T12:57:19.187 回答
7

标准库例程不是为处理volatile对象而设计的。最简单的解决方案是在对易失性内存进行操作之前将其读入普通内存:

void ss_load_char(volatile char *digits) {
  char buf[BUFSIZE];
  int i = 0;
  for (i = 0; i < BUFSIZE; ++i) {
    buf[i] = digits[i];
  }
  int l=strlen(buf);
  ...
}

BUFSIZE是易失性存储器区域的大小。

根据易失性存储器的配置方式,您可能应该调用例程来复制内容,而不仅仅是使用循环。请注意,这memcpy不起作用,因为它不是为使用volatile内存而设计的。

于 2012-11-29T12:58:02.783 回答
5

编译器警告仅意味着 strlen() 不会将您的指针视为易失性指针,即在计算字符串长度时它可能会将指针缓存在寄存器中。我想,你没问题。

一般来说,volatile意味着编译器不会缓存变量。看这个例子:

extern int flag;
while (flag) { /* loop*/ }

如果 ,这将永远循环flag != 0,因为编译器假定标志没有“从外部”更改,就像不同的线程一样。如果你想等待其他线程的输入,你必须这样写:

extern volatile int flag;
while (flag) { /* loop*/ }

现在,每次循环循环时,编译器都会真正查看标志。这可能更符合我们在这个例子中的意图。

回答您的问题:如果您知道自己在做什么,只需使用int l=strlen((char*)digits).

于 2012-11-29T12:55:05.097 回答