关于补码的转换规则(十进制与二进制之间的转化问题)是阅读本文的基础。
/2019年5月31日19:07:59/
此篇博文是我在学习C语言过程中在编译程序时不经意间的疑惑,经过后续的理解,才有了以下的理解。有不足的地方希望指正!
首先,给出当时引起我疑惑的例程:
#include<stdio.h>
int main()
{
signed char i = -1; //C语言中并未指定char类型的变量是signed/unsigned
int j = -1; //最好指定
short k = -1;
printf("%d\n", i);
printf("%u\n", i);
printf("%#X\n", i);
printf("%#X\n", j);
printf("%#X\n", k);
return 0;
注释 | 我是尺寸上例程序中之所以指定char类型是以防由于不同的机器之间存在结构差异导致char类型在进行整型提升时,进行符号扩展/左侧补零情形不一 。 |
---|---|
关于符号扩展/左侧补零属于整型转换范畴,在我另一篇博文中有详细说明,下附地址:https://blog.csdn.net/Xuefu_836782243/article/details/90704589 |
输出结果为: |
---|
-1 |
4294967295(0XFFFFFFFF) |
0XFFFFFFFF |
0XFFFFFFFF |
0XFFFFFFFF |
此处便产生以下两点疑问: |
---|
1、为何定义为char类型(8位)的i变量,以及short类型(16位)的k变量为何在输出时变为了32位的数据? |
2、为何以带符号整型(%d)可以直接输出 -1,而以无符号整型(%u)输出时,却是这样一个大数? |
针对疑问1: |
---|
通过查阅资料后发现,这种出现char与short类型位数提升的现象在C语言中叫作整型提升。 |
根据参考《C程序设计语言第2版》,对整型提升有以下定义:
如果int能够表示原始类型中的所有数值,那么这个数值就被转换成int型,否则,它被转换成unsigned int型,这种规则叫作整型提升。
值得注意的是,这种规则只存在于所有的整型变量中,其他类型不存在这种提升现象。对于整型提升现象,归根结底就是一句话:当程序中出现char以及short类型的运算时,short与char先转换成int类型再参与运算。
根据此规律我们对程序中出现的现象做出的解释如下:
当定义char i = -1时,计算机以补码的形式进行存储其存储若按char类型分配1个字节的存储空间来考虑则存储二进制为(-1的补码:0XFF)但是由于存在整型提升,此时的char分配的应该为4个字节(int类型分配4个字节),而4个字节存储的-1的补码为(0XFFFFFFFF)。故无论是char还是short类型,均以0XFFFFFFFF作为输出结果。
针对疑惑二: |
---|
第二个问题有了第一个问题做铺垫,就非常简单了。由疑惑一的解答可知无论是char还是short类型的变量,都会进行整型提升。
由疑惑一的解答可知,无论是short还是char类型的 -1 均是以0XFFFFFFFF存储在计算机中的,当以%d,即带符号十进制整型输出,其最高位为符号位,其余31位才是数据位,由于其最高位的符号位为1表示负数,其转换成十进制,需要按补码规则进行取反加1得到,经过补码运算后得到其带符号整型输出为 -1 我相信懂得补码转换规则的都应该能理解这一点。 |
而对于使用%u无符号整型输出后,其输出结果为这样一个大数是因为,无符号输出,数据最高位不再表示符号位,故数据位有32位。0XFFFFFFFF转换成十进制则为2^32-1 = 4294967295 |
总结
在学习或者运行程序的过程中,我们总会遇到一连串的疑惑,为什么会出现这样的一个数。我想真正的学习可能就藏在这些为什么的后面。就像本文所写的例程可以说是最简单的理论,但是其身后还是蕴含着如此之多的知识点。单看一本书一切都是那么的顺利,可当动手运行第一个代码时,疑问才会喷涌而出!对书本上的文字将会有一个全新的体会。此篇博文只是学习心得,如果有不正确的地方,希望大家多多交流,互相进步!