目录
以下例子都是在32位机器下进行..
1.整形(char)类型的存储:
<1>整形:
在计算机中所有数字都是以二进制的补码形式存储。
原码:正整数的原码就是其二进制数字,其他位往前补0,例如123的二进制为:1111011
由于是在32位下,所以将其用0补齐,变成00000000 00000000 00000000 01111011
正整数的 原码 反码 补码 都是一样的!!!。
对于负数而言,其原码与整数的原码类似,只有一点不同,例如123的原码补齐后是
00000000 00000000 00000000 01111011,那么对于-123而言,他与整数的区别仅仅在于第一位的不同,那么-123的原码应该为10000000 00000000 00000000 01111011。
原码搞定后接下来就是 反码,规则就是首位(符号位不变)其他位取反(1变0,0变1),相应的,-123的反码应该为:11111111 11111111 11111111 10000100。
最后就是补码,补码就是将其反码+1,显然,-123的补码应该为:11111111 11111111 11111111 10000101;
<2>char 类型:
将一个整数存储在char里面时,会发生截断,就是把一个数的补码,只保留其最后八位,拿上面的的123来说,只保存0111011,其它与整形类似。
2.奇奇怪怪的题目
T1:
1.
#include <stdio.h>
int main()
{
char a= -1;
signed char b=-1;
unsigned char c=-1;
printf("a=%d,b=%d,c=%d",a,b,c);
return 0;
}
理由:a,b在内存中都是以补码存在,由于是有符号char类型,所以会发生阶段,只存了11111111 这个二进制序列,在使用时会发生整型提升,自动补齐剩下的位(补符号位,也就是1),最后以整形的方式打印,那么正好是-1;
而对于c而言,他存储也是以11111111的形式存储,但是他是无符号char类型,那么在发生整形提升时会自动补0,则最后提升为:00000000 000000000 000000000 111111111,由于是无符号,此时编译器认为他的原码反码补码相同,则最后解析该二进制序列就是255.
TIPS:所有无符号数在发生整型提升时通通补0!!!
T2
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
理由:
类似的,a要发生截断,而-128的补码是:11111111 11111111 11111111 10000000,发生截断以后储存在内存中的就是10000000,而最后要求以无符号整形的形式打印,那么他就会自动发生整形提升,会自动补齐符号位(1),那么它就变成了11111111 11111111 11111111 10000000,由于是用无符号整形来解析这个二进制序列,所以认为这个就是他的原码,则最后输出的就是这个很大的数字
T3:
3.
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
显然,这个与上面的类似128的原码反码都是一样的 :00000000 00000000 00000000 10000000,发生截断以后,就变成1000000,这不是与上面的-128一样吗?那么解释就与T2一样。
T4:
int i= -20;
unsigned int j = 10;
printf("%d\n", i+j);
解释:
数字的运算都是以补码的形式,由于最后是以整形形式来解析,就算j是一个无符号整数,他的加减和有符号相同,所以最后输出的-10就很容易想通了。
T5 :
unsigned int i;
for(i = 9; i >= 0; i--)
{
printf("%u\n",i);
}
结果:死循环
解释:
在i变成0之前,他都会正常的打印,因为都是无符号数,但是在i变为-1的时候,由于在内存中是以补码的形式存在,-1的补码为32个1,又是以无符号整形解析,那么此时认为32个1全部有效,则会变成一个很大的数字依次向下递减,最后变成-1的时候又与刚才类似,所以是一个死循环!
T6:
int main()
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a));
return 0;
}
解释:
strlen是测量数组长度的,在0(\0)的时候截止!
在解释之前,先讲解一下char short……等等一些数据储存的取值范围的讲解。
对于无符号char类型,他的二进制序列是一个A88的全排列,则从00000000变为11111111的一个过程,由于是无符号来解析,则认为他的所有位斗有效,而11111111解析过来正好是255,则无符号char类型的取值范围就是0~255;
对于有符号char类型,他的二进制序列也是一个A88的全排列,也是从0000000变为11111111的一个过程,而由于他是一个有符号类型,则最高位1就是他的符号位,因此他的正整数最大取值就是01111111解析过来就是127,而对于111111111来说,他是以补码类型存储,那么他的原码就是10000001,解析过来就是-1,以此类推,它可以储存到-127,但是由于规定,最小值就应该存储的-128,所以有符号char,他的取值范围就是-128~127
则可以由此得出,有符号char类型的变化如下图:
则由题意,数组就会从0 -1 -2……一直到127 126…… 1 0,恰好是255个元素,上面就解释的通了,类似的可以得到short int的取值范围了。
T7 :
#include <stdio.h>
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello world\n");
}
return 0;
}
结果:死循环
解释:经过上面的解释,无符号char的取值范围是0~255,到256只有就会自动变为0,形成四虚幻
<3.浮点数的存储>
引入:
在一个32位的精度(float类型中),我们把第一位记为S,把后面八位记为E,把再后面二十三位记为M(64位,double类型只是E,M所占位数的区别)
S称为符号位,正数记为0,负数为1;
E称为指数位,M为有效数字位
例如,二进制数字:1068.5432可以与十进制类似记为1.0685432*2^3,E的存储就是把指数+127(double类型+1024),而M的存储是把1舍弃,存储后面的0685432,
两个特例:
如果指数全为1,则高达255次方,而2^32次方是42亿,显然2^255次方太大了,直接认为是无穷大量
如果指数为全0,此时就是-255次方,接近于0,则此时认为他就是0;
基于上面的理解,看如下代码:
int main()
{
int n = 9;
float* pFlo = (float*)&n;
printf("n:%d\n", n);
printf("*pFlo:%f\n", *pFlo);
*pFlo = 9.0;
printf("num:%d\n", n);
printf("*pFlo:%f\n", *pFlo);
return 0;
}
解释:9就不用多解释了
对于0.000000来说,9在内存中的存储形式00000000 00000000 00000000 00001001,此时pFlo是一个浮点类型指针,对其进行解引用访问就会把上面的二进制序列自动解析为浮点序列,显然他的指数位为全0,则输出的就是0;
之后对*pFlo进行解引用访问为浮点类型9.0,根据上面的知识,他在内存中应该是0 10000010 001 0000 0000 0000 0000 0000这样存储,但是在打印的时候使用%d打印,则自动解析为上面的数字
打印9.0000则是一个正常的现象..
以上就是数据的存储