Gccarmnoneeabi 10.3.1在编译arm-cortexm3代码时做出了我意想不到的行为

我最近在使用gccarm工具链开发stm32,在编译一个freertos程序的时候,由于gccarm做出了一个让我十分意外的行为,让我花了一晚上才找到这个bug

这是出现了bug的函数的源代码:


```c++
void SHT2x_Read(void *pvParameters){
    SHT2x_Struct *sht2x = (SHT2x_Struct *)pvParameters;
    static TwoWire SHT20_Wire = TwoWire(sht2x->SDA_Pin, sht2x->SCL_Pin);
    SHT2x sht2x_sensor;
    sht2x_sensor.begin(&SHT20_Wire);
 
    while(1){
        sht2x_sensor.read();
        float SHT_Temp = sht2x_sensor.getTemperature();  //为了尽可能减小锁申请时间,要省去两次函数调用
        float SHT_Humi = sht2x_sensor.getHumidity();
        
        if(xSemaphoreTake(xMutex, 1000) == pdTRUE){
            //do something
            SHT_msg.SHT_Humi = SHT_Humi;
            SHT_msg.SHT_Temp = SHT_Temp;
            xSemaphoreGive(xMutex);
        }
        vTaskDelay(1000);
    }
}

可以看到,我在变量SHT20_Wire前加了一个static关键字,如此程序才正常运行,但是按照逻辑来讲,就算我不加这个关键字,程序也应该能正常运行

这是不加static关键字产生的汇编代码

```xml
0x08006f54: 30 b5               push    {r4, r5, lr}
0x08006f56: c3 b0               sub    sp, #268    ; 0x10c
0x08006f58: 42 78               ldrb    r2, [r0, #1]
0x08006f5a: 01 78               ldrb    r1, [r0, #0]
0x08006f5c: 09 a8               add    r0, sp, #36    ; 0x24
0x08006f5e: 01 f0 93 fc         bl    0x8008888 <_ZN7TwoWireC2Emm>
0x08006f62: 68 46               mov    r0, sp
0x08006f64: 03 f0 ca fc         bl    0x800a8fc <_ZN5SHT2xC2Ev>
0x08006f68: 09 a9               add    r1, sp, #36    ; 0x24
0x08006f6a: 68 46               mov    r0, sp
0x08006f6c: 03 f0 a6 fd         bl    0x800aabc <_ZN5SHT2x5beginEP7TwoWire>
0x08006f70: 0d e0               b.n    0x8006f8e <_Z10SHT2x_ReadPv+58>
0x08006f72: 11 4b               ldr    r3, [pc, #68]    ; (0x8006fb8 <_Z10SHT2x_ReadPv+100>)
0x08006f74: 5d 60               str    r5, [r3, #4]
0x08006f76: 1c 60               str    r4, [r3, #0]
0x08006f78: 00 23               movs    r3, #0
0x08006f7a: 1a 46               mov    r2, r3
0x08006f7c: 19 46               mov    r1, r3
0x08006f7e: 0f 48               ldr    r0, [pc, #60]    ; (0x8006fbc <_Z10SHT2x_ReadPv+104>)
0x08006f80: 00 68               ldr    r0, [r0, #0]
0x08006f82: fe f7 46 fa         bl    0x8005412 <xQueueGenericSend>
0x08006f86: 4f f4 7a 70         mov.w    r0, #1000    ; 0x3e8
0x08006f8a: ff f7 a3 f8         bl    0x80060d4 <vTaskDelay>
0x08006f8e: 68 46               mov    r0, sp
0x08006f90: 03 f0 28 fe         bl    0x800abe4 <_ZN5SHT2x4readEv>
0x08006f94: 68 46               mov    r0, sp
0x08006f96: 03 f0 17 fd         bl    0x800a9c8 <_ZN5SHT2x14getTemperatureEv>
0x08006f9a: 04 46               mov    r4, r0
0x08006f9c: 68 46               mov    r0, sp
0x08006f9e: 03 f0 2f fd         bl    0x800aa00 <_ZN5SHT2x11getHumidityEv>
0x08006fa2: 05 46               mov    r5, r0
0x08006fa4: 4f f4 7a 71         mov.w    r1, #1000    ; 0x3e8
0x08006fa8: 04 4b               ldr    r3, [pc, #16]    ; (0x8006fbc <_Z10SHT2x_ReadPv+104>)
0x08006faa: 18 68               ldr    r0, [r3, #0]
0x08006fac: fe f7 22 fc         bl    0x80057f4 <xQueueSemaphoreTake>
0x08006fb0: 01 28               cmp    r0, #1
0x08006fb2: de d0               beq.n    0x8006f72 <_Z10SHT2x_ReadPv+30>
0x08006fb4: e7 e7               b.n    0x8006f86 <_Z10SHT2x_ReadPv+50>
0x08006fb6: 00 bf               nop
0x08006fb8: 80 04               lsls    r0, r0, #18
0x08006fba: 00 20               movs    r0, #0
0x08006fbc: 7c 04               lsls    r4, r7, #17
0x08006fbe: 00 20               movs    r0, #0

这是加上了static关键字产生的汇编代码:

0x08006f90: 30 b5               push    {r4, r5, lr}
0x08006f92: 8b b0               sub    sp, #44    ; 0x2c
0x08006f94: 1d 4b               ldr    r3, [pc, #116]    ; (0x800700c <_Z10SHT2x_ReadPv+124>)
0x08006f96: 1b 68               ldr    r3, [r3, #0]
0x08006f98: 13 f0 01 0f         tst.w    r3, #1
0x08006f9c: 07 d0               beq.n    0x8006fae <_Z10SHT2x_ReadPv+30>
0x08006f9e: 01 a8               add    r0, sp, #4
0x08006fa0: 03 f0 dc fc         bl    0x800a95c <_ZN5SHT2xC2Ev>
0x08006fa4: 1a 49               ldr    r1, [pc, #104]    ; (0x8007010 <_Z10SHT2x_ReadPv+128>)
0x08006fa6: 01 a8               add    r0, sp, #4
0x08006fa8: 03 f0 b8 fd         bl    0x800ab1c <_ZN5SHT2x5beginEP7TwoWire>
0x08006fac: 19 e0               b.n    0x8006fe2 <_Z10SHT2x_ReadPv+82>
0x08006fae: 42 78               ldrb    r2, [r0, #1]
0x08006fb0: 01 78               ldrb    r1, [r0, #0]
0x08006fb2: 17 48               ldr    r0, [pc, #92]    ; (0x8007010 <_Z10SHT2x_ReadPv+128>)
0x08006fb4: 01 f0 98 fc         bl    0x80088e8 <_ZN7TwoWireC2Emm>
0x08006fb8: 14 4b               ldr    r3, [pc, #80]    ; (0x800700c <_Z10SHT2x_ReadPv+124>)
0x08006fba: 01 22               movs    r2, #1
0x08006fbc: 1a 60               str    r2, [r3, #0]
0x08006fbe: 15 48               ldr    r0, [pc, #84]    ; (0x8007014 <_Z10SHT2x_ReadPv+132>)
0x08006fc0: 03 f0 6e fe         bl    0x800aca0 <atexit>
0x08006fc4: eb e7               b.n    0x8006f9e <_Z10SHT2x_ReadPv+14>
0x08006fc6: 14 4b               ldr    r3, [pc, #80]    ; (0x8007018 <_Z10SHT2x_ReadPv+136>)
0x08006fc8: 5d 60               str    r5, [r3, #4]
0x08006fca: 1c 60               str    r4, [r3, #0]
0x08006fcc: 00 23               movs    r3, #0
0x08006fce: 1a 46               mov    r2, r3
0x08006fd0: 19 46               mov    r1, r3
0x08006fd2: 12 48               ldr    r0, [pc, #72]    ; (0x800701c <_Z10SHT2x_ReadPv+140>)
0x08006fd4: 00 68               ldr    r0, [r0, #0]
0x08006fd6: fe f7 1c fa         bl    0x8005412 <xQueueGenericSend>
0x08006fda: 4f f4 7a 70         mov.w    r0, #1000    ; 0x3e8
0x08006fde: ff f7 79 f8         bl    0x80060d4 <vTaskDelay>
0x08006fe2: 01 a8               add    r0, sp, #4
0x08006fe4: 03 f0 2e fe         bl    0x800ac44 <_ZN5SHT2x4readEv>
0x08006fe8: 01 a8               add    r0, sp, #4
0x08006fea: 03 f0 1d fd         bl    0x800aa28 <_ZN5SHT2x14getTemperatureEv>
0x08006fee: 04 46               mov    r4, r0
0x08006ff0: 01 a8               add    r0, sp, #4
0x08006ff2: 03 f0 35 fd         bl    0x800aa60 <_ZN5SHT2x11getHumidityEv>
0x08006ff6: 05 46               mov    r5, r0
0x08006ff8: 4f f4 7a 71         mov.w    r1, #1000    ; 0x3e8
0x08006ffc: 07 4b               ldr    r3, [pc, #28]    ; (0x800701c <_Z10SHT2x_ReadPv+140>)
0x08006ffe: 18 68               ldr    r0, [r3, #0]
0x08007000: fe f7 f8 fb         bl    0x80057f4 <xQueueSemaphoreTake>
0x08007004: 01 28               cmp    r0, #1
0x08007006: de d0               beq.n    0x8006fc6 <_Z10SHT2x_ReadPv+54>
0x08007008: e7 e7               b.n    0x8006fda <_Z10SHT2x_ReadPv+74>
0x0800700a: 00 bf               nop
0x0800700c: 8c 04               lsls    r4, r1, #18
0x0800700e: 00 20               movs    r0, #0
0x08007010: 90 04               lsls    r0, r2, #18
0x08007012: 00 20               movs    r0, #0
0x08007014: 31 6f               ldr    r1, [r6, #112]    ; 0x70
0x08007016: 00 08               lsrs    r0, r0, #32
0x08007018: 84 04               lsls    r4, r0, #18
0x0800701a: 00 20               movs    r0, #0
0x0800701c: 80 04               lsls    r0, r0, #18
0x0800701e: 00 20               movs    r0, #0

我不是很懂汇编,但是这两段汇编代码似乎表明,当我不加上static关键字的时候,SHT20_Wire的地址没有被存入栈中,致使这个地址存放的值在之后的进程中被修改,造成了系统错误

但是我在后面调用了sht2x_sensor.begin函数并将SHT20_Wire的地址传进去,按我的想法来说,编译器应该假设这个类中存在私有变量和这个地址相关联,如此则不应该把这个地址优化掉,而是应该把他保存起来,使之后的函数调用是正常的,但事实却不是这样

我问了问一个比我懂gcc多很多的朋友,他说凡是被取地址的变量,按理来说,不应该被优化,我也相当疑惑为什么gcc会做出这样的优化,是因为我的版本太低吗?还是说这是被写在gcc文档中的优化点吗?

我使用的平台:Platformio IDE in VSCode(ST STM32)
我的工具链:gccarmnoneeabi @ 1.100301.220327 (10.3.1)

等待回答ing

【以下回答由 GPT 生成】

根据提供的代码和问题描述,我可以给出以下解答:

首先,通过观察给出的汇编代码,我们可以看到在加了static关键字的情况下,编译器生成了一条新的指令 "sub sp, #268"。这条指令的作用是创建了一个局部变量的空间,而向局部变量分配内存空间的过程称为为"栈帧分配"。

在没有加static关键字的情况下,我们则没有看到这条指令。这是因为没有用到static关键字,编译器会认为变量是一个普通的自动变量,它将在每次函数调用时创建并在函数返回时销毁。

通过加入static关键字,变量SHT20_Wire被定义为静态变量,它在函数执行时只会被初始化一次,并且其内存空间将在程序运行时一直存在。因此,无论函数多少次被调用,SHT20_Wire的内存空间始终都在那里。

在这种情况下,栈帧分配主要用于开辟局部变量的内存空间,而不是为静态变量分配内存空间。这样可以避免在函数的每次调用时重新分配和销毁静态变量所占用的内存空间,从而提高程序的性能。

因此,加了static关键字后,程序能够正常运行。

总结: - static关键字用于将变量声明为静态变量,其内存空间在程序运行时一直存在。 - 在使用static关键字后,编译器将为静态变量分配内存空间,并将其初始化一次。 - 在没有使用static关键字时,变量将作为自动变量处理,它在每次函数调用时创建并在函数返回时销毁。 - 加入static关键字可以避免在函数的每次调用时重新分配和销毁静态变量所占用的内存空间,提高程序性能。

希望这个解答对你有帮助,如果你还有任何疑问,请随时提出。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^