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;
//}

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
STM32F042是一款基于ARM Cortex-M0内核的微控制器,它具有丰富的外设和功能,适用于各种应用场景。其中,ADC(模数转换器)是其中一个重要的外设,用于将模拟信号转换为数字信号。 在STM32F042中,ADC的引脚映射关系如下: - PA5对应ADC_IN5 - PA6对应ADC_IN6 - PA7对应ADC_IN7 要使用ADC功能,需要进行相应的配置和编程。下面是一个示例代码,演示了如何使用回调函数来读取PA5、PA6和PA7对应的模拟信号: 首先,需要进行ADC的初始化配置,包括时钟使能、通道选择、采样时间等。然后,定义一个回调函数,在该函数中读取并处理ADC转换结果。 ```c #include "stm32f0xx.h" // ADC回调函数 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { // 读取ADC转换结果 uint16_t adc_value = HAL_ADC_GetValue(hadc); // 处理ADC转换结果 // ... } int main(void) { // 初始化GPIO和ADC // 配置ADC通道和采样时间 ADC_ChannelConfTypeDef sConfig = {0}; sConfig.Channel = ADC_CHANNEL_5; // 选择通道5 sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; // 设置采样时间 HAL_ADC_ConfigChannel(&hadc, &sConfig); // 启动ADC转换 HAL_ADC_Start_IT(&hadc); // 使用中断模式启动转换 while (1) { // 主循环 // ... } } ``` 以上是一个简单的示例代码,通过回调函数`HAL_ADC_ConvCpltCallback`来处理ADC转换结果。在该函数中,可以读取并处理ADC转换结果,具体的处理方式根据实际需求进行编写。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值