我试图弄清楚为什么在关闭以下代码的编译器优化后停止工作:
bool send_atcmd(char* atcmd, char* expected_response, unsigned int timeout)
{
volatile char* buf = uart_get_rx_buf(UART_MODEM);
bool response_match = false;
if (modem_powered_on)
{
__delay_cycles((unsigned long)500 * DELAY_MS);
uart_clear_rx_buf(UART_MODEM);
uart_puts(UART_MODEM, atcmd);
uart_putc(UART_MODEM, '\r');
timer_ms = 0;
while (!response_match && timer_ms <= timeout)
{
//__nop();
if (strstr(buf, expected_response) != NULL)
response_match = true;
}
uart_clear_rx_buf(UART_MODEM);
}
return response_match;
}
Run Code Online (Sandbox Code Playgroud)
代码使用msp430-gcc编译,buf指向接收调制解调器操作的uart端口的缓冲区.一切正常,直到没有优化(-O0),但是当 条件为假时,当while循环上的优化完成时timer_ms <= timeout,strstr(buf, expected_response)永远会返回!NULL.这是因为buf的内容似乎没有更新.
但是,if (strstr(buf, expected_response) != NULL)在while循环之前放置任何东西
,例如取消注释nop()会使代码正常工作.
将buf在ISR更新.
甚至__nop()为什么有帮助?
它会导致未定义的行为volatile char *向strstr提供.
C99附件J.2(这是未定义行为的事项列表)
尝试通过使用具有非volatile限定类型的左值来引用使用volatile限定类型定义的对象(6.7.3)
这是有道理的,因为在strstr操作期间可能会更新字符,这可能会造成严重破坏.
一个建议的解决方法是使用锁或其他机制来确保不更新字符,然后将字符复制到非易失性缓冲区,然后将该缓冲区传递给strstr.
或者,如果有一个可以安全地从uart读取到非易失性存储区域的函数,那么这将起作用.