当前位置:首页 > 公众号精选 > 嵌入式客栈
[导读]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获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

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

据韩媒《朝鲜日报》消息,三星集团已确认已决定将适用于三星电子等部分关联公司的“高管每周工作 6 天”扩大到整个集团。三星子公司的人力资源团队直接通过口头、群聊和电子邮件向高管传达了这一新政,而非正式信函的形式。

关键字: 三星

4月23日,深圳传音控股股份有限公司发表了2023年年度报告。数据显示,2023年,该公司手机整体出货量约1.94亿部。

关键字: 传音 智能手机

最新消息,美国参议院以 79 票赞成、18 票反对的压倒性多数,通过了一项可能导致 TikTok 在美国被禁的法案,该法案要求字节跳动公司出售 TikTok,否则将面临禁令。TikTok 最多有 12 个月的时间从母公司...

关键字: 美国 TikTok 字节跳动

业内消息,近日数码博主@手机晶片达人在社交媒体发文表示,苹果公司正在研发自家的 AI 服务器芯片,采用台积电的 3nm 工艺,预估将于 2025 年下半年量产。台积电是苹果最重要的合作伙伴,目前苹果的大部分 3nm 产能...

关键字: 苹果 AI服务器芯片 台积电 3nm

业内消息,近日苹果公司公布了2023财年供应链名单。其中,中国大陆地区新进8家企业,有4家企业被剔除;中国台湾地区供应商新进2家企业,同样有4家企业被剔除。

关键字: 苹果 供应链

随着科技的飞速发展,人工智能已经逐渐走进我们的生活。从智能手机到自动驾驶汽车,人工智能正不断改变着我们的日常体验。然而,这只是科技革命的一个起点。

关键字: 人工智能 AI 自动驾驶

业内消息,上周第 21 届华为分析师大会在深圳开幕,大会期间华为云核心网产品线总裁高治国表示,华为携手浙江移动完成了全球首个 5G-A(5.5G)核心网智能差异化体验保障方案的预商用部署。

关键字: 华为 5.5G

业内消息,上周国务院新闻发布会介绍了2024年一季度工业和信息化发展情况。工业和信息化部新闻发言人、总工程师赵志国在发布会上表示,一季度中国 5G 手机出货量达 5643 万部,同期占比 83.7%,反映出高端或者智能...

关键字: 工信部 手机

业内消息,近日供应链大厂群光电子(Chicony Electronics)在官网披露报告声称于 4 月 15 日遭到黑客组织 Hunters International 攻击,据称超过 1.2TB 内部数据(共计 414...

关键字: 供应链 群光电子 黑客入侵

业内消息,上周谷歌公司解雇了28名员工,原因是这些员工在谷歌纽约和加州森尼维尔的办公室静坐10小时,抗议谷歌与以色列签订的价值12亿美元的云计算合同。

关键字: 云计算 谷歌
关闭
关闭