当前位置:首页 > 公众号精选 > 嵌入式客栈
[导读]1、简单聊一聊     今天为大家推荐一首周深的《大鱼》,真的是上天赐予的嗓子,与这首歌曲真的绝配!如果上天再给我一次选择的机会,我还是选择当一名程序员。     好了,之前为大家写了一篇<【典藏】别怪"浮点数"太坑(C语言版本)>,很多小伙伴反馈到希望作

1、简单聊一聊

    今天为大家推荐一首周深的《大鱼》,真的是上天赐予的嗓子,与这首歌曲真的绝配!如果上天再给我一次选择的机会,我还是选择当一名程序员。
    好了,之前为大家写了一篇<【典藏】别怪"浮点数"太坑(C语言版本)>,很多小伙伴反馈到希望作者也补充一些整形数相关的坑。仔细想想平时我们用整形数比浮点数多得多,而且整形数的细节还真不少,为了便于以后大家编码等,这里作者根据自己的一些经验记录一下。

1、整形的存储

1)说说数据的存储 

    数据对于存储器而言都是二进制的0101...,也就是我们所说的机器码。而我们所定义的类型就相当于确定了这块内存占据多大的位置和以怎么这样的方式进行解析。比如说16进制:0xFF,在unsigned char中表示255,而在signed char中表示-1,其他数据类型也是类似的道理。如果你再看得抽象一点把指针拿过来一起理解,可以把变量看成是地址固定不变的指针。

2)聊聊原码、反码、补码 

    先上理论知识:(注意:浮点数不是以该方式存储)

原码:
  • 正数:符号位为0,其他为正常二进制。

  • 负数:符号位为1,其他为绝对值二进制。

反码:
  • 正数:与原码一致。

  • 负数:符号位为1,其他位按位取反。

补码:
  • 正数:与原码一致。

  • 负数:反码+1。

    对于整形数计算机上的存储都是以补码的形式进行存储,那么对于正数就按照正常的二进制进行存储,而负数则对原码进行反码+1存储,在我们平时进行仿真或者调试过程中用无符号输出负数会有一个非常大的数据,其实这个数据就是该负数的补码。

    比如:char类型的-3,其原码为1000 0011-->反码为11111100-->其补码为:11111101,如果我们采用unsigned char类型显示则为:253,如果我们知道原码那就反过来进行计算即可。同样其他整形数据类型也是一样的实现方式。

2、整形溢出问题

1)为什么用补码存储? 

    大家应该都知道1 - 1 = 1 + (-1) = 0,那么计算机为了简化运算就把(-1)用另外一种方式存储,这样计算机就只需要进行加法运算,于是便产生了补码。同样四则运算中的乘法和除法运算都可以通过加法进行表示。(有一种"道生一、一生二、二生三、三生万物"的精妙)

    通过上面我们也可以看出直接用原码进行计算,最终结果竟然成为了-2,明显不符合;而采用补码计算,由于采用byte计算,进位被截断了,从而获得了最终的结果0.同时使用补码的形式也规避掉了原码中0映射问题,如下图所示。

2)数据溢出问题 

    这里我以char和unsigned char类型来进行说明,对于其他整形数据同样分析即可,首选我们来看看使用补码以后的数据表示范围问题,目前最经典的图形表示方法就是采用环形表示,如下图:

    这样表示的好处是,一旦数据溢出,直接顺着变化的方向即可找到对应的值。这里也贴出实验的代码如下:

 1#include <stdio.h>
2#include <stdlib.h>
3/********************************************************
4 * Fuction:测量char类型数据溢出问题 
5 * Author :(公众号:最后一个bug) 
6 *******************************************************/

7int main(int argc, char *argv[]) {
8    char Val           = 5;
9    char Val1          = 123;
10    unsigned char Val2 = 5;
11    unsigned char Val3 = 123;
12    int i = 0;
13
14    printf("char    |     char    |     uchar   |     uchar\n");
15    printf("-----------------------------------------------\n");        
16    for(i = 0;i < 9;i++)
17    {
18        printf("%4d  ******  ",--Val);  
19        printf("%4d  ******  ",++Val1);
20        printf("%4d  ******  ",--Val2);
21        printf("%4d\n",++Val3);
22    }
23    printf("\n公众号:最后一个bug\n"); 
24}

    最终输出的结果与我们的环形结构是相符合的,结果如下:

3)它来了!!! 

    提个几个问,有符号char类型中的-128取相反数会获得什么值?无符号取相反数又等于什么呢?不防敲个代码实验下,代码简单直接上结果:

    我们可以得出结论:相反数直接关于环形对称。同样其他的数据类型也是同样的性质,仅仅只是数据范围变大了。


3、算数转化

1)算数转化(前方高能)  

    首先我们来看一下一段简单的代码:(前方高能!!)

 1#include <stdio.h>
2#include <stdlib.h>
3/********************************************************
4 * Fuction: 算数转化测试
5 * Author :(公众号:最后一个bug) 
6 *******************************************************/

7int main(int argc, char *argv[]) {
8    int Val1 = -2;
9    unsigned int  Val2 = 1;
10
11    if(Val1 > Val2)
12    {
13        printf("-2 > 1\n");     
14    }
15    else
16    {
17        printf("-2 < 1\n");     
18    }
19    printf("\n公众号:最后一个bug\n"); 
20}

    了解算数转化概念的小伙伴应该都知道,该程序并不会输出我们常规的-2 < 1,而是输出-2 > 1这个结果,这个与我们的常规结果有点不符合。(眼见为实,下图看结果)

2)汇编来坐镇  

    作者第一个接触到这个问题的时候都怀疑人生了,这C也太坑了,一言不合就把我给弄得团团转。既然C这样做肯定有其原因吧,分析疑难杂症从汇编做起:(DevC++,gcc-32bit)

    我们看到if语句对应的汇编cmp指令和jbe跳转指令;其中jbe用于判断无符号跳转指令,那么会把EAX直接当成无符号类型进行处理,从而得到了我们上述的结果,如果你把上面的代码Val2改成int类型,然后查看汇编文件会得到如下结果:

    其中唯一的区别就是jle,该汇编指令为有符号条件转移指令,你可以编译一下能够得到我们想要的结果。

3)算数转化总结 

    我们这里所说的算数转化其实就是一种隐式的强制类型转化,我们平时大部分都是使用的显示强制类型转化,就像我们上面的程序,其实这种情况是比较危险的,我们大部分汇编指令都是具有相同类型操作数,那么如果操作数类型不同,系统会根据数据类型的优先级进行自动转化。(大家可以参考下面的类型进行对应处理)

    原则:数据都是优先转化为长数据类型,浮点与整形优先转化为浮点运算,无符号与有符号优先转化为无符号。


4、整形数据的提升

    经常有很多小伙伴把整形提升与算数转化混合一起谈,其实算数转化是为了让操作数一致而进行的隐式类型转化,而整形提升是对于短类型转化为长类型进行处理的一种方式,这个是必然的过程,不管类型是否一致。

 1#include <stdio.h>
2#include <stdlib.h>
3/********************************************************
4 * Fuction:整形提升 
5 * Author :(公众号:最后一个bug) 
6 *******************************************************/

7int main(int argc, char *argv[]) {
8    char          Val1 = 1;
9    unsigned char Val2 = 2;
10
11    printf("sizeof(Val1)        = %d\n",sizeof(Val1)); 
12    printf("sizeof(-Val2)       = %d\n",sizeof(-Val1)); 
13    printf("sizeof(Val2 - Val1) = %d\n",sizeof(Val2 - Val1)); 
14    printf("\n公众号:最后一个bug\n"); 
15}

    最终输出的结果:

解析一下:

    对于整形提升,其实主要是为了增加CPU运算效率,就跟我们前面说补码一样,CPU只想用加法就能够实现4则运算,那么其处理数据也是一样的,大部分的寄存器都是32位的(仅仅对于32位机器),比如上面汇编中的EAX寄存器,CPU就想直接处理32位的数,并且效率也高,计算完毕以后再转化为对应的类型获得最后的结果,对于char等等这些短数据类型在进行运算或者比较的过程中都会采用int类型进行处理,如果有更加长的数据类型会优先转化为更长的数据类型。


5、最后小结

    估计大家看完以后都不敢随便写代码了,其实不要慌,在编码的过程中一定要对每个变量的范围和变化都要了然如胸,在进行运算操作的时候最好是相同类型,切记最好不要将有符号和无符合混合使用,如果硬要混合记得显式强制类型转换。

    好了,这里是公众号:“最后一个bug”,一个为大家打造的技术知识提升基地。同时非常感谢各位小伙伴的支持,我们下期精彩见!

推荐好文  点击蓝色字体即可跳转

【典藏】别怪"浮点数"太坑(C语言版本)

 【经典】解析一个STM32在线升级实例(usart版本)

【典藏】深度剖析单片机程序的运行(C程序版) 

【重磅】剖析MCU的IAP升级软件设计(设计思路篇)

 【解惑】到底是"时间片"?还是"分时轮询"?

GUI必备知识之“告别”乱码(浅显易懂)

【典藏】大佬们都在用的结构体进阶小技巧

听说因为代码没"对齐"程序就奔了?(深度剖析)

【典藏】自制小型GUI界面框架(设计思想篇)

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭