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?什么是安全的解决方法?
答案 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)
投射挥发性物质。