STM32 類型隱性轉換 爲何 6 + (-20) > 6 ???

在STM32平臺上輸入一下代碼段:

int main(void)
{
    uint8_t a = 6;
    int8_t b = -20;

    if(b+a>6){
        LED0=1;
    }else{
        LED0=0;
    }
}

程序最終會執行,LED0=0,即表示 6+(-20)<6。

通過MDK的反彙編得到代碼:

    10:     uint8_t a = 6; 
0x080002FC 2106      MOVS     r1,#0x06
    11:     int8_t b = -20; 
    12:  
0x080002FE F06F0213  MVN      r2,#0x13
    13:     if(b+a>6){ 
0x08000302 1850      ADDS     r0,r2,r1
0x08000304 2806      CMP      r0,#0x06
0x08000306 DD03      BLE      0x08000310
    14:         LED0=1; 
    15:     }else{ 
0x08000308 2001      MOVS     r0,#0x01
0x0800030A 4B04      LDR      r3,[pc,#16]  ; @0x0800031C
0x0800030C 6018      STR      r0,[r3,#0x00]
0x0800030E E002      B        0x08000316
    16:         LED0=0; 
    17:     } 
0x08000310 2000      MOVS     r0,#0x00
0x08000312 4B02      LDR      r3,[pc,#8]  ; @0x0800031C
0x08000314 6018      STR      r0,[r3,#0x00]
    18: } 
0x08000316 2000      MOVS     r0,#0x00
0x08000318 4770      BX       lr

把uint8_t 修改爲uint16_t ,得到的彙編代碼:

    10:     uint16_t a = 6; 
0x080002FC 2106      MOVS     r1,#0x06
    11:     int16_t b = -20; 
    12:  
0x080002FE F06F0213  MVN      r2,#0x13
    13:     if(b+a>6){ 
0x08000302 1850      ADDS     r0,r2,r1
0x08000304 2806      CMP      r0,#0x06
0x08000306 DD03      BLE      0x08000310
    14:         LED0=1; 
    15:     }else{ 
0x08000308 2001      MOVS     r0,#0x01
0x0800030A 4B04      LDR      r3,[pc,#16]  ; @0x0800031C
0x0800030C 6018      STR      r0,[r3,#0x00]
0x0800030E E002      B        0x08000316
    16:         LED0=0; 
    17:     } 
0x08000310 2000      MOVS     r0,#0x00
0x08000312 4B02      LDR      r3,[pc,#8]  ; @0x0800031C
0x08000314 6018      STR      r0,[r3,#0x00]
    18: } 
0x08000316 2000      MOVS     r0,#0x00
0x08000318 4770      BX       lr

這跟uint8_t時的彙編代碼一樣,沒有變化。

當把uint8_t 修改爲uint32_t 時,即代碼如下:

int main(void)
{
    uint32_t a = 6;
    int32_t b = -20;

    if(b+a>6){
        LED0=1;
    }else{
        LED0=0;
    }
}

得到的彙編也變了:

    10:     uint32_t a = 6; 
0x080002FC 2106      MOVS     r1,#0x06
    11:     int32_t b = -20; 
    12:  
0x080002FE F06F0213  MVN      r2,#0x13
    13:     if(b+a>6){ 
0x08000302 1850      ADDS     r0,r2,r1
0x08000304 2806      CMP      r0,#0x06
0x08000306 D903      BLS      0x08000310
    14:         LED0=1; 
    15:     }else{ 
0x08000308 2001      MOVS     r0,#0x01
0x0800030A 4B04      LDR      r3,[pc,#16]  ; @0x0800031C
0x0800030C 6018      STR      r0,[r3,#0x00]
0x0800030E E002      B        0x08000316
    16:         LED0=0; 
    17:     } 
0x08000310 2000      MOVS     r0,#0x00
0x08000312 4B02      LDR      r3,[pc,#8]  ; @0x0800031C
0x08000314 6018      STR      r0,[r3,#0x00]
    18: } 
0x08000316 2000      MOVS     r0,#0x00
0x08000318 4770      BX       lr

3個程序段得到的代碼,只有在跳轉指令不同(LED0=1上面一句):

uint8_t 和uint16_t 中,跳轉指令是:0x08000306 DD03      BLE      0x08000310

而在uint32_t 中,跳轉指令是:0x08000306 D903      BLS      0x08000310

區別就在與BLE 和BLS,爲搞懂這兩個指令的含義,需要找ST官方的文檔PM0056,在該文檔的3.8.5章節由說到跳轉指令:

PS:BLE和BLS是B指令,不是BL指令,LE和LS是條件碼。

可選條件碼在剛文檔的表23, Table 23: Condition code suffixes on page 57:

簡言之,BLE就是有符號類的小於等於,BLS就是無符號類的小於等於。

明白了以上一點,就再繼續分析。

STM32爲32爲的CPU,其寄存器就是32位的,在執行

    uint32_t a = 6;
    int32_t b = -20;
或
    uint16_t a = 6;
    int16_t b = -20;
或
    uint8_t a = 6;
    int8_t b = -20;

和
    a+b

以上程序時,得到的彙編代碼都是一樣的:

0x080002FC 2106      MOVS     r1,#0x06
0x080002FE F06F0213  MVN      r2,#0x13
0x08000302 1850      ADDS     r0,r2,r1

最後得到的結果就是a+b = R0=0xFFFF FFF2,而這個R0的值,到底是把它當有符號看,還是無符號看,就要看後面的指令了,STM32就只是個存儲。

前面說到,BLE就是有符號類的小於等於,BLS就是無符號類的小於等於。對於uin32_t 彙編得到的是BLS,因此R0這個數就是一個無符號的數,所以 a+b = 0xFFFF FFF2 = 4294967282 > 6 

對於uint8_t 彙編得到的數是BLE,因此R0這個數是一個有符號數,所以 a+b = 0xFFFF FFF2 = -14 < 6

 

因此對於STM32來說,並非所有情況都能使 6 + (-20) > 6 成立。

那麼什麼時候這個條件成立?先說類型轉換規則:

(1)、進行運算的兩個變量的數據類型長度,若都小於32位,則都轉換爲有符號32位數據,即int32_t

(2)、若兩變量中數據類型長度大的那一個,且它的數據類型大於等於32位,則另一個數據轉換爲與數據類型大的那一個一樣

(3)、若兩變量中數據類型長度一樣,若存在無符號數,則都轉換爲無符號數。

根據規則,判斷如下情況:

/********************************/
    uint8_t a = 6;
    int8_t b = -20;
    
    uint16_t a = 6;
    int8_t b = -20;
    
    uint32_t a = 6;
    int8_t b = -20;
    
    uint64_t a = 6;
    int8_t b = -20;
    /********************************/
    
    /********************************/
    uint8_t a = 6;
    int16_t b = -20;
    
    uint16_t a = 6;
    int16_t b = -20;
    
    uint32_t a = 6;
    int16_t b = -20;
    
    uint64_t a = 6;
    int16_t b = -20;
    /********************************/
    
    /********************************/
    uint8_t a = 6;
    int32_t b = -20;
    
    uint16_t a = 6;
    int32_t b = -20;
    
    uint32_t a = 6;
    int32_t b = -20;
    
    uint64_t a = 6;
    int32_t b = -20;
    /********************************/
    
    /********************************/
    uint8_t a = 6;
    int64_t b = -20;
    
    uint16_t a = 6;
    int64_t b = -20;
    
    uint32_t a = 6;
    int64_t b = -20;
    
    uint64_t a = 6;
    int64_t b = -20;
    /********************************/

可以使用代碼自行實驗:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define TYPE            uint8_t

#define FirstVar        -20
#define SeconedVar      6

int main()
{
    char *p="int64_t";

    uint8_t a = FirstVar;
    TYPE b = SeconedVar;

    if(a+b>6){
        printf("uint8_t %d + %s %d  > 6 \r\n",FirstVar,p,SeconedVar);
    }else{
        printf("uint8_t %d + %s %d  < 6 \r\n",FirstVar,p,SeconedVar);
    }


    uint16_t c = FirstVar;
    TYPE d = SeconedVar;
    if(c+d>6){
        printf("uint16_t %d + %s %d  > 6 \r\n",FirstVar,p,SeconedVar);
    }else{
        printf("uint16_t %d + %s %d  < 6 \r\n",FirstVar,p,SeconedVar);
    }

    uint32_t e = FirstVar;
    TYPE f = SeconedVar;
    if(e+f>6){
        printf("uint32_t %d + %s %d  > 6 \r\n",FirstVar,p,SeconedVar);
    }else{
        printf("uint32_t %d + %s %d  < 6 \r\n",FirstVar,p,SeconedVar);
    }

    uint64_t g = FirstVar;
    TYPE h = SeconedVar;
    if(g+h>6){
        printf("uint64_t %d + %s %d  > 6 \r\n",FirstVar,p,SeconedVar);
    }else{
        printf("uint64_t %d + %s %d  < 6 \r\n",FirstVar,p,SeconedVar);
    }


    getchar();
    return 0;
}

//int main()
//{
//    char *p="uint8_t";
//
//    int8_t a = FirstVar;
//    TYPE b = SeconedVar;
//
//    if(a+b>6){
//        printf("int8_t %d + %s %d  > 6 \r\n",FirstVar,p,SeconedVar);
//    }else{
//        printf("int8_t %d + %s %d  < 6 \r\n",FirstVar,p,SeconedVar);
//    }
//
//
//    int16_t c = FirstVar;
//    TYPE d = SeconedVar;
//    if(c+d>6){
//        printf("int16_t %d + %s %d  > 6 \r\n",FirstVar,p,SeconedVar);
//    }else{
//        printf("int16_t %d + %s %d  < 6 \r\n",FirstVar,p,SeconedVar);
//    }
//
//    int32_t e = FirstVar;
//    TYPE f = SeconedVar;
//    if(e+f>6){
//        printf("int32_t %d + %s %d  > 6 \r\n",FirstVar,p,SeconedVar);
//    }else{
//        printf("int32_t %d + %s %d  < 6 \r\n",FirstVar,p,SeconedVar);
//    }
//
//    int64_t g = FirstVar;
//    TYPE h = SeconedVar;
//    if(g+h>6){
//        printf("int64_t %d + %s %d  > 6 \r\n",FirstVar,p,SeconedVar);
//    }else{
//        printf("int64_t %d + %s %d  < 6 \r\n",FirstVar,p,SeconedVar);
//    }
//
//
//    getchar();
//    return 0;
//}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章