(char) 指针的 GCC 优化没有意义

GCC optimization of (char) pointers makes no sense

我正在为 STM32 MCU 项目使用 STM32 Cube IDE 1.8.0 版。 生成器设置是默认的。它设置为“外部构建器”。

arm-none-eabi-gcc --version
arm-none-eabi-gcc (GNU Tools for STM32 9-2020-q2-update.20201001-1621) 9.3.1 20200408 (release) Copyright (C) 2019 Free Software Foundation, Inc.

Properties->C/C++ Build->Settings->Tool Settings MCU GCC compiler command为gcc -c,All options内容为

-mcpu=cortex-m4 -std=gnu11 '-D__weak=__attribute__((weak))' '-D__packed=__attribute__((__packed__))' -DUSE_HAL_DRIVER -DSTM32F412Rx -c -I../Drivers/STM32F4xx_HAL_Driver/Inc -I../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy -I../Middlewares/Third_Party/FreeRTOS/Source/include -I../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 -I../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F -I../Middlewares/ST/STM32_USB_Device_Library/Core/Inc -I../Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc -I../Drivers/CMSIS/Device/ST/STM32F4xx/Include -I../Drivers/CMSIS/Include -Os -ffunction-sections -fdata-sections -Wall -fstack-usage --specs=nano.specs -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mthumb

关注-Os!

现在,如果我使用以下代码(片段)

bool ESP32_WifiCommCmds_ConnectToAP ( char* ssid, char* password, char* mac )
{
    char cmd [ 96 ] = { 0 };
    char *ssidEscaped, *passwordEscaped;
    ESP32_ModuleCommCmds_EscapeSpecialCharacters ( ssid, &ssidEscaped );
    if ( ssidEscaped == NULL )
    {
        return false;
    }
    ESP32_ModuleCommCmds_EscapeSpecialCharacters ( password, &passwordEscaped );
    if ( passwordEscaped == NULL )
    {
        free ( ssidEscaped );
        return false;
    }
    if ( strlen(ssidEscaped) + strlen(passwordEscaped) + strlen(mac) + 17 > sizeof(cmd) )
    {
        free ( ssidEscaped );
        free ( passwordEscaped );
        return false;
    }
    // THE FOLLOWING IF ELSE WILL GET OPTIMIZED !!!!!!
    if ( mac == NULL )
    {
        // THIS WILL GET OPTIMIZED OUT
        sprintf ( cmd, "AT+CWJAP=\"%s\",\"%s\",,,1", ssidEscaped, passwordEscaped );
    }
    else
    {
        // THIS WILL STAY
        sprintf ( cmd, "AT+CWJAP=\"%s\",\"%s\",\"%s\",,1", ssidEscaped, passwordEscaped, mac );
    }
    free ( ssidEscaped );
    free ( passwordEscaped );
    char buffer [ 48 ] = { 0 };
    // Send cmd to ESP is left out here, for simplification
}

并且在业务逻辑中,只调用这个函数: success = ESP32_WifiCommCmds_ConnectToAP ( data->ssid, data->password, NULL );

有人建议,优化后的代码将删除 if ( mac == NULL ),因为它始终是 true。但事实上恰恰相反。

问题出在strlen(mac)这一行,但我不知道为什么会这样。我需要解释,因为我担心无论我在这里做错什么,都不会影响我的其余代码。

PS:如果您想自己检查,只需搜索生成的二进制文件以包含“AT+CWJAP=...”字符串。只有其中一个在那里(除非你关闭优化)。

如果您调用 strlen(mac),则允许​​编译器假定 mac 永远不会为 null。

推理是这样的:

A) 如果 mac 不为空,那么它假设正确并且它基于该假设所做的一切都是正确的。

B) 如果 mac 为空,那么您调用 strlen(NULL) 会触发未定义的行为。由于未定义的行为意味着它绝对可以做任何事情,所以它所做的任何事情都必须是正确的。

因此,无论调用此函数时的参数是什么,假设 mac 不为 null 的实现都是正确的。

请注意,这一切都发生在编译函数的实现时,它永远不会像您想象的那样查看您在调用函数的代码中所做的事情。