STM32 类型隐性转换 为何 6 + (-20) 6 ???

2024-01-24 23:18
文章标签 类型 转换 stm32 20 隐性

本文主要是介绍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,#0x0611:     int8_t b = -20; 12:  
0x080002FE F06F0213  MVN      r2,#0x1313:     if(b+a>6){ 
0x08000302 1850      ADDS     r0,r2,r1
0x08000304 2806      CMP      r0,#0x06
0x08000306 DD03      BLE      0x0800031014:         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        0x0800031616:         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,#0x0611:     int16_t b = -20; 12:  
0x080002FE F06F0213  MVN      r2,#0x1313:     if(b+a>6){ 
0x08000302 1850      ADDS     r0,r2,r1
0x08000304 2806      CMP      r0,#0x06
0x08000306 DD03      BLE      0x0800031014:         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        0x0800031616:         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,#0x0611:     int32_t b = -20; 12:  
0x080002FE F06F0213  MVN      r2,#0x1313:     if(b+a>6){ 
0x08000302 1850      ADDS     r0,r2,r1
0x08000304 2806      CMP      r0,#0x06
0x08000306 D903      BLS      0x0800031014:         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        0x0800031616:         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      6int 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;
//}

 

这篇关于STM32 类型隐性转换 为何 6 + (-20) 6 ???的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/641343

相关文章

java Long 与long之间的转换流程

《javaLong与long之间的转换流程》Long类提供了一些方法,用于在long和其他数据类型(如String)之间进行转换,本文将详细介绍如何在Java中实现Long和long之间的转换,感... 目录概述流程步骤1:将long转换为Long对象步骤2:将Longhttp://www.cppcns.c

在Java中将XLS转换为XLSX的实现方案

《在Java中将XLS转换为XLSX的实现方案》在本文中,我们将探讨传统ExcelXLS格式与现代XLSX格式的结构差异,并为Java开发者提供转换方案,通过了解底层原理、性能优势及实用工具,您将掌握... 目录为什么升级XLS到XLSX值得投入?实际转换过程解析推荐技术方案对比Apache POI实现编程

Python使用FFmpeg实现高效音频格式转换工具

《Python使用FFmpeg实现高效音频格式转换工具》在数字音频处理领域,音频格式转换是一项基础但至关重要的功能,本文主要为大家介绍了Python如何使用FFmpeg实现强大功能的图形化音频转换工具... 目录概述功能详解软件效果展示主界面布局转换过程截图完成提示开发步骤详解1. 环境准备2. 项目功能结

使用Python实现网页表格转换为markdown

《使用Python实现网页表格转换为markdown》在日常工作中,我们经常需要从网页上复制表格数据,并将其转换成Markdown格式,本文将使用Python编写一个网页表格转Markdown工具,需... 在日常工作中,我们经常需要从网页上复制表格数据,并将其转换成Markdown格式,以便在文档、邮件或

Python将字符串转换为小写字母的几种常用方法

《Python将字符串转换为小写字母的几种常用方法》:本文主要介绍Python中将字符串大写字母转小写的四种方法:lower()方法简洁高效,手动ASCII转换灵活可控,str.translate... 目录一、使用内置方法 lower()(最简单)二、手动遍历 + ASCII 码转换三、使用 str.tr

Java如何将文件内容转换为MD5哈希值

《Java如何将文件内容转换为MD5哈希值》:本文主要介绍Java如何将文件内容转换为MD5哈希值的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java文件内容转换为MD5哈希值一个完整的Java示例代码代码解释注意事项总结Java文件内容转换为MD5

使用Java将实体类转换为JSON并输出到控制台的完整过程

《使用Java将实体类转换为JSON并输出到控制台的完整过程》在软件开发的过程中,Java是一种广泛使用的编程语言,而在众多应用中,数据的传输和存储经常需要使用JSON格式,用Java将实体类转换为J... 在软件开发的过程中,Java是一种广泛使用的编程语言,而在众多应用中,数据的传输和存储经常需要使用j

Java实现视频格式转换的完整指南

《Java实现视频格式转换的完整指南》在Java中实现视频格式的转换,通常需要借助第三方工具或库,因为视频的编解码操作复杂且性能需求较高,以下是实现视频格式转换的常用方法和步骤,需要的朋友可以参考下... 目录核心思路方法一:通过调用 FFmpeg 命令步骤示例代码说明优点方法二:使用 Jaffree(FF

C语言中的常见进制转换详解(从二进制到十六进制)

《C语言中的常见进制转换详解(从二进制到十六进制)》进制转换是计算机编程中的一个常见任务,特别是在处理低级别的数据操作时,C语言作为一门底层编程语言,在进制转换方面提供了灵活的操作方式,今天,我们将深... 目录1、进制基础2、C语言中的进制转换2.1 从十进制转换为其他进制十进制转二进制十进制转八进制十进

Pandas进行周期与时间戳转换的方法

《Pandas进行周期与时间戳转换的方法》本教程将深入讲解如何在pandas中使用to_period()和to_timestamp()方法,完成时间戳与周期之间的转换,并结合实际应用场景展示这些方法的... 目录to_period() 时间戳转周期基本操作应用示例to_timestamp() 周期转时间戳基