数据的存储和部分注意不到的“隐式转换”及例题解析

注意:以下内容部分为我自己的理解,不一定完全正确,请适当参考。

一、常见类型所占位数及数据范围
printf("sizeof(char)=%d\n", sizeof(char));
printf("sizeof(short)=%d\n", sizeof(short));
printf("sizeof(int)=%d\n", sizeof(int));
printf("sizeof(long)=%d\n", sizeof(long));
printf("sizeof(long)=%d\n", sizeof(long long));
printf("sizeof(float)=%d\n", sizeof(float));
printf("sizeof(double)=%d\n", sizeof(double));

在这里插入图片描述
    通过上述运行结果可以得出,不同的数据类型占用不同的字节空间,我们知道计算机是用二进制位来存储数据的,而一个字节又是八个二进制位,我们以占一个字节空间的char类型来进行探讨。
    char类型分为有符号char和无符号char,虽然都占用一个字节空间即八个二进制位,但其表示数据范围不同。
    1、有符号char:有符号类型就是采用首位来作为符号位,0表示正,1表示负。其他位表示数据,最大的数是111 1111,最小是000 0000,加上符号位之后,如果符号位为0,那就是0000 0000 ~ 0111 1111,转换成十进制数就是0 ~ 127如果符号位为1,这就有点问题了,是1000 0000 ~ 1111 1111吗,如果是这样,那1000 0000不是也是0吗,这不就有正0和负0两个0了吗,显然是不合理的,其实是这样,应该是1000 0001 ~ 1000 0000,表示的是-1 ~ -128,这就是我们常说的范围-2^7 ~ 2^7-1,至于为什么,等下再说。
    2、无符号char:所谓无符号就是说我们只表示正数。这样也就不需要什么符号位了,八个二进制位表示的数据范围为0000 0000 ~ 1111 1111,即0 ~ 255,这没有什么可说的。

二、数据的存储

数据在计算机中是以补码形式存储的,正数的补码就是原码,负数的补码是其符号位不变的情况下,数据位取反加1。接着上边说一下为什么要用补码存储以及补码为什么要这样算。
1、为什么要用补码存储,资料上是这么说的
    (1)补码存储可以解决正0和负0的二义性问题。
    (2)补码存储使得符号位和数据位统一参与运算,简化了电路,节约成本。
补码的设计就是依赖了有限位数据运算可能溢出的特点,用补码存储的数据运算时,直接丢失溢出位。
    关于正0和负0的问题前边说过,当用补码存储之后有一个有意思的一点是从-1 ~ -127刚好来了个转置,也不存在-1之前有-0的可能性了。
    另外一点,我们用于表示-128的1000 0000和-127也连起来了,1000 0001 - 1 = 1000 0000完全没有问题。而且-1加一也等于0,1111 1111 + 1 =0000 0000(丢弃溢出位),这也是完全正确的。
2.补码为什么要这么算通过上述描述应该也有所理解了,最妙的一点就在于将负数整体转置,好巧不巧的有构成了另一特点,正数,0,负数完美的结合了起来。而且最小的负数1000 0000减一等于最大的正数0111 1111,好像在能表示的范围内构成了一个环,0->1->最大正数->最小负数->-1->0。这个环形成的原因和对其的理解是很重要的,后边的好多题目基本都依赖它。

三、可能的“隐式转换”

    课本上所描述的类型之间的隐式转换是在进行运算时,占低字节数的类型的数据自动向高字节类型的数据转换,但是我所说的是另外一种,或者说都不能称之为隐式转换,更像是由于解码方式的不同导致的数据改变
    举个例子:

int main()
{
	unsigned char a = 128;
	char b = a;
	printf("%d\n", b);
	return 0;
}

    这个代码细心一点的人就会发现其中的端倪,char类型范围是-128 ~ 127,所以将a赋给b时,就会出现问题,我们先看一下结果。
在这里插入图片描述
    出现这一现象,首先想到的是128赋给char类型变量赋不过去,可是真的是赋不过去吗?我们知道,把一个占高字节的类型数据赋给占低字节的类型变量是,可能会发生截断,使得只保存低位字节数据。但是这里都是占一个字节是不会发生截断的呀,先看下图。
在这里插入图片描述
    无符号字符型128的补码和有符号字符型-128的补码完全相同,这就说明并不是赋值错误,赋值过去的数据完全相同,只是在解码时把它作为有符号类型,所以才会出现这样的结果。
    到这里,总结一下吧:
    (1)数据总是以它的补码存入内存,将一个字面常亮或变量赋值给一个变量时,存不下就截断只赋值低位,存的下就赋值过去。
    (2)我们所看到的数据发生改变其实都是解码方式不同的原因,从前到后真实存入内存的数据并没有发生改变。

四、两个例题

1、

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

结果:
在这里插入图片描述
原因是a+b的值是300,直接输出什么都不影响,就是300,但是将这个结果赋值给c时,300的补码是1 0010 1100,赋给c截断将最高位丢弃,剩余值正好是44,。
2、

int main()
{
	char a = -1;
	int count = 0;
	while (a != 0)
	{
		a--;
		count++;
	}
	printf("%d\n", count);
}

结果:
在这里插入图片描述
这个题和之前说的那个环就有点关系了,a是char类型,范围是-128 ~ 127,初始值为-1,从-1 ~ -128count加128次,a再减一时a = 127,然后从127 ~ 1count加127次,然后a-1=0,循环终止,所以count最终等于255。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值