'while'循环优化太多 - 为什么nop()修复它?

tml*_*tml 3 c

我试图弄清楚为什么在关闭以下代码的编译器优化后停止工作:

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()为什么有帮助?

M.M*_*M.M 5

它会导致未定义的行为volatile char *向strstr提供.

C99附件J.2(这是未定义行为的事项列表)

尝试通过使用具有非volatile限定类型的左值来引用使用volatile限定类型定义的对象(6.7.3)

这是有道理的,因为在strstr操作期间可能会更新字符,这可能会造成严重破坏.

一个建议的解决方法是使用锁或其他机制来确保不更新字符,然后将字符复制到非易失性缓冲区,然后将该缓冲区传递给strstr.

或者,如果有一个可以安全地从uart读取到非易失性存储区域的函数,那么这将起作用.

链接到相关的SO线程