表达式求值(上):整型提升

        哈喽小伙伴们大家好,这几天已经有点怀疑人生了,俗话说“一切快乐和自信源自于无知”,古人诚不欺吾也!最近几天我的快乐都没有了,原因就是将要写的这篇文章——表达式求值。其实这期内容鹏哥讲的我几天前就看完了,这几天一直在痛苦的查阅相关资料中(当然学习掌握到这种重难点知识还是另有一番成就感的),因为看完鹏哥对于此处的讲解,我直接变身十万个为什么,心中的疑惑和不解实在太多,时至今日我仍然有很多不解之处,之所以现在开始动手写文章实在是我查阅的资料已经非常多了,必须梳理一下,不然太乱了。所以这篇文章必定会有一些问题,因为我的理解还不够,有些甚至是错的,所以也是希望小伙伴们发现问题及时沟通反馈,学海无涯我们共同进步呀!

        好了,我们直接开始本期内容,本期我们分两大部分,整型提升和问题表达式,整型提升是重中之重。

1整型提升

        肯定是先介绍定义说一下什么是整型提升啦,我这里就不粘贴官方定义了,因为实在是晦涩难懂,直接以我的理解从新说一个我个人的定义。首先,整型提升是一种偷偷的行为,我们(像以前快乐无知的我)是看不见的,所以也就不知道,官方的名称叫做“隐式类型转换”,下面我就从为什么发生和什么时候发生给小伙们进行讲解,才疏学浅,还望大家互相学习,有不对的欢迎评论区指出,让我们共同进步。

1.1为什么发生整型提升

        所谓整型提升,想了解就要知道为什么要进行整型提升。原因呢就是我们的CPU在处理表达式运算时,一般使用的是整形运算器ALU,这个运算器的操作数的字节长度一般就是int的字节长度,同时int也是CPU的通用寄存器的长度,也就是说虽然存在机器语言可以让计算机执行两个8bit位(单字节,例如char型)的数字计算,但是实际上绝大多数CPU是不能进行这样的计算的,因为并没有这样的容器来“盛放”他们。如同吃饭一样,我们家的盘子都是放4个馒头的大盘子,即使你只吃一个馒头,我也不可能去给你买个放一个馒头的小盘子,也是用这个大盘子装。而内存相当于我们家橱柜,它的空间是可以定义的,你可以直接把馒头放里面,它就占一个馒头的空间。我向橱柜放一个馒头,就像我定义“char a = 1”,然而当我吃得时候,我得拿一个盘子装,或者说我加热馒头的时候,我得用盘子装,这里的“吃”,“加热”就相当于表达式运算,我家只有装4个馒头的盘子,那就只能用它来盛放。而当我吃得时候,或者没吃掉放回柜子里,再或者我就把他放在盘子里放进橱柜,前两种它就占我的胃或者柜子的一个馒头位置,而放盘子就占柜子一个盘子,也就是4个馒头的位置,这取决于表达式运算的结果我们用什么接收。这样我相信大家就可以很好地理解为什么会发生整型提升了。

        知道了为什么发生整型提升之后,我们还是来看一下官方的定义:C的整型算术运篡总是至少以缺省整型类型也就是默认整形类型的精度来进行的。为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。

1.2什么时候发生整型提升
        现在相信小伙伴们就可以懂了吧,其实就是人家的盘子都是放4个馒头的嘛,你算一个馒头或者两个馒头(char和short),也得用这大盘子装。那么知道了为什么,下面来说一下什么时候生整型提升。其实如果为什么我领悟了80,那么什么时候我感觉我只知道60。这几天我查阅了大量的资料,也没有找到一个比较满意的答案,在我目前的理解看来,只要是表达式计算,表达式里有小于int的,都要提升成int。但是对于表达式计算包括什么,这个我就不是很理解,目前来看应该是前面讲的操作符都是表达式计算,唯一出现问题的就是取反操作符“!”,这个咱们后面在细讲,因为在查阅尝试的过程中我遇到了相当多的问题。后面一一给大家分享。那么对于什么时候发生,总结来说有两点:

        1.表达式求值,有大于整型int的转化为相应整型,没有大于int整型或者最大为int整型,则char(unsigned char)和short(unsigned short)全部转化为int型。

        2.如果表达式内不包括比int更大的类型,但是原始类型值域不可以被int表示,那么转为unsigned int。其实类似于有比int更大的类型,就是当表达式中有unsigned int型时,全部转化为unsigned int型。虽然int与unsigned int都是4字节,但是unsigned int比int值域大,所以为保证精度,还是会都整型提升为unsigned int。

        unsigned是无符号数的意思哈,比如char能存储-128到127,而unsigned char同样占一字节,能表示的值域为0到255,这是因为虽然同为1字节8bit,无符号数8位都用来表示数字,而有符号数只有7位能作为二进制表示值,首位为符号数,所以一般认为unsigned类型相较于原类型更大,同时为表达式中最大类型时要发生整型提升到unsigned型。

1.3整型提升规则

        有符号数:向前补符号位(正补0,负补1)

        无符号数数:向前补0

1.4整型提升例题

        好了,概念到此结束,所谓实践出真知,接下来上实战:

例1:

int main()
{
	char a = 3,
		 b = 127,
		 c = 0;
	c = a+b;
	printf("%d\n", c);
	return 0;
}

        大家不妨猜一下结果,相信大家如果不知道整型提升的话,应该第一反应就是有溢出和截断,但是对于结果是多少就不知道了,那么学了整型提升,让我们来一起算一下,因为涉及32位二进制,所以还是放到代码里给大家说:

例2:

int main()
{
	char a = 0;
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(+a));
	printf("%d\n", sizeof(!a));
	return 0;
}

        这题的答案为1,4,1,相信大家有很多疑问,我来说一下。首先第一个问题:sizeof不是不进行计算吗,才讲过的呀,我才看过阿g的文章,你可别骗我?这里说一下,sizeof是不产生计算结果,也就是说括号内的操作并不会真的对相应表达式内的元素所在的地址的值产生改变,但是表达式作为sizeof的一个参数,他肯定是要产生一个结果供sizeof计算其大小,所以sizeof内的表达式是会开辟新的内存空间进行计算并产生结果的,但是计算完成被sizeof计算完后内存就会释放掉,不会影响参数值。

         讲清sizeof的问题,还有!a操作怎么没有将表达式结果整型提升为int?这个问题我查阅了相当多的资料,但是由于问题不好描述,查到的大部分也是避重就轻或者没在意这个问题,结果就是并没有官方的确定的答案,下面是我个人的一点理解,仅供参考。

        在思考为什么的过程中,我把char改为了short,这时候理论上来说应该是“!”操作不发生整型提升,sizeof求得结果为2,但是我运行的结果让我大吃一惊:

         居然是1,我恍然大悟,“!b”根本就不是没有发生整型提升(当然我也不确定发生过,查了许久没得到确切的结果),而是表达式经过取反操作结果变为bool型,bool型占一字节。为了印证我有做了一个实验:

        事实证明,我的结论是正确的,取反操作“!”确实会把表达式变为bool型,解决了这个疑惑,我又去把剩下的单目操作符都试了试,我惊讶的发现++a居然sizeof求值也为1:

         经过我一番思考,我大概理解了原因:++a它就等价于a = a+1,这样来看的话虽然“a+1”计算肯定发生了整型提升,但是结果赋值给a又发生了截断,而++与--作为操作符时,操作数必须是可修改的左值(因为++a只是a = a+1的简写,此表达式等号左边必须为变量),即一个在内存开辟了空间的变量,所以无论如何,结果都会存入这个变量本身,所以本题中sizeof算得的就是a和b的大小。做实验验证结果如下:

        受此启发,我发现又一个操作符也不太对劲,那就是取地址“&” 。为什么说他不对劲呢,这是因为虽然我在实验时sizeof(&a)确实等于4,似乎发生了整型提升,但是我在理解++a之后就感觉不对劲了,因为看似简单的操作符,其中居然隐藏着“=”,思考之下,我认为sizeof(&a)= 4是因为在32位系统下,得到的指针变量大小就是4罢了,而不是所谓的a经过&操作发生了整型提升。实验果然验证了猜想,切换为64位系统,sizeof(&a)= 8。

        最终经过对各种奇怪的问题的探究和理解,结合整型提升那晦涩难懂的定义,我似乎理解了那个定义,从而对整型提升有了更加深入的理解。以下三条为大重点!!!

       一、 那就是计算机CPU一般根本不具有直接计算int型以下类型的能力(除非根据需求特制的计算机CPU),也就是说,只要是小于int型的数据类型参与表达式的计算,那么不管结果如何,在用到这个值时都一定会发生整型提升,因为计算机CPU内最小的盘子就是放4个馒头的。

        二、而用sizeof(一个表达式)来证明这个表达式有没有发生整型提升是错误的,是不可靠的!因为sizeof计算的是结果的大小,之所以有时候似乎可以证明发生了整型提升,那是因为表达式计算的结果是不存储的,即结果是单纯的一个计算结果,没有被保存到任何容器内,否则sizeof计算的将是那个容器的大小。只有表达式的结果是大杂烩,这个结果才是所有值里最大那个类型。

        三、发生整型提升是于个体而言的,是否发生是由两个将要计算的值得类型决定的!只要是类型小于int型的值在被使用计算时都一定会发生整型提升。而两个类型大于int型的值计算时,如果类型不同,一样还是要被提升为二者之间大的类型,float与double进行计算时float要提升为double。其目的都是为了让结果更精确。

        好了,那么这期内容就是这些了,相信大家看了一定会有所收获,因为我在研究的时候也是常常是豁然开朗。这样学习过程让人非常的舒适。虽然知道的太多会变不快乐,但是收获的快乐也是让人流连忘返的。由于本期内容有大量的个人理解和见解,所以必然有不足,缺陷甚至于错误,希望小伙伴们能够有思考的接收呀!

        如果觉得这篇文章对你有帮助欢迎收藏点赞转发,如果发现问题或者有不解之处也欢迎小伙伴们在评论区交流哦。最后喊出我们的口号“关注小白阿g,让小白不再白学!”亲爱的小伙伴们下期见。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值