如何安全地转换/复制volatile变量?

时间:2012-11-29 12:42:07

标签: c volatile

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复制到非易失性var?什么是安全的解决方法?

3 个答案:

答案 0 :(得分:9)

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

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

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

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

答案 1 :(得分:4)

标准库例程不适用于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内存。

答案 2 :(得分:3)

编译器警告仅表示strlen()不会将指针视为易失性,即它可能会在计算字符串长度时将指针缓存在寄存器中。我猜,你也可以。

通常,volatile表示编译器不会缓存变量。看看这个例子:

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

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

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

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

回答你的问题:如果你知道自己在做什么,只需使用int l=strlen((char*)digits)投射挥发性物质。