一. 整数在内存中的存储
二.大小端字节序和字节序判断
例题精讲
练习一
int check_sys()
{
int a = 1;
return (*(char*)&a);//小端返回1,大端返回0
}
int main()
{
if (check_sys() == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
练习二
C语言中整型算术运算总是至少以缺省整型类型的精度来进行的。为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整 型提升。原码的整型提升:改变类型直接写出新的原码即可补码的整型提升:有符号整型提升是按照变量的数据类型的符号位来提升的无符号整型提升,高位补0
%d - 以十进制的形式打印有符号的整型
char a = -1 整型提升至 整型 其次存储
原码 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
反码 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
补码 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
截断补码并存储
1 1 1 1 1 1 1 1 - a
由于以十进制打印有符号的整型
所以首先整型提升至整型
补码 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 取反 原码 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 加1 => -1
signed char b = -1 整型提升至 有符号整型 其次存储
原码 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
反码 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
补码 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
截断补码并存储
1 1 1 1 1 1 1 1 - b
由于以十进制打印有符号的整型
所以首先整型提升至有符号整型
补码 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 取反 原码 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 加1 打印十进制有符号的整型
=> -1
unsigned char c = -1
-1先整型提升至有符号整型
原码 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
反码 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
补码 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
截断补码并存储
1 1 1 1 1 1 1 1 - c
由于以十进制打印有符号的整型
所以首先整型提升至无符号整型
补码 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
由于打印十进制有符号的整型
反码 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
原码 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
=> 255
练习三
-128只有补码 1000 0000
先整形提升至 有符号整型
补码 11111111111111111111111110000000
截断存储 10000000 - a
由于打印无符号的整型
所以首先整型提升至有符号整型
补码 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0
由于打印无符号的整型
反码 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0
原码 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0
=> 4294967168
128先整型提升至 无符号整型
原码 00000000000000000000000010000000
截断存储 10000000 -a
由于打印无符号整型
所以首先整型提升 有符号整型
补码 11111111111111111111111110000000
由于打印无符号整型
反码 11111111111111111111111110000000
原码 11111111111111111111111110000000
=> 4294967168
练习四
char的取值范围是 -128~127
当 i=128,-1-128=-129,就会越界了
a[128]=-129;
-129先整型提升至 有符号整型
原码 10000000 00000000 00000000 10000001
反码 111111111 111111111 111111111 011111110
补码 111111111 111111111 111111111 011111111
截断存储 01111111
补码 01111111
反码 01111111
原码 01111111
=> 127
所以当a[128]=-129时,存进去的是127代表的字符
以此类推
i=0 a[0]=-1
......
i=127 a[127]=-128
i=128 a[128]=127
......
i=255 a[255]=0='\0'
所以strlen(a)=255
练习五
unsigned char的取值范围 0~255
i=256的时候按道理会跳出循环
但事实并非如此
256首先整型提升至 无符号整型
原码 00000000 00000000 00000001 00000000
反码 00000000 00000000 00000001 00000000
补码 00000000 00000000 00000001 00000000
截断存储 00000000
补码 00000000
反码 00000000
原码 00000000
=> 0
所以当i=256时存进去的是0
所以会陷入死循环
这里按道理i=-1的时候会跳出循环
但事实并非如此
-1
原码 10000000 00000000 00000000 00000001
反码 111111111 111111111 111111111 111111110
补码 111111111 111111111 111111111 111111111
存储
111111111 111111111 111111111 111111111
补码 111111111 111111111 111111111 111111111
反码 111111111 111111111 111111111 111111111
原码 111111111 111111111 111111111 111111111
打印无符号整型
=>4294967295
......
依次类推
向下递减
无限循环
补充练习
&a是整个数组的地址 &a+1的地址大小是a[3]后面一个的地址,但代表一块16字节的地址
int * 将&a+1转换为 单独四字节的地址
ptr1[-1]==*(ptr1-1)==*(&a[3]+1-1)==*(&a[3])==a[3]==4
a=&a[0] (int) a将地址转为10进制,然后再加1
0x0012ff40,1244992,加一,1244993,
将1244993转为16进制为0x0012ff41
实际上跳过了一个字节
int型有四个字节
跳过一个字节访问到的就是 00 00 00 02,由于是小端存储模式
输出的话就是 20 00 00 00
注意点:这是在32位情况下运行的,64位情况下地址是8个字节,用int会发生截断
应选择用 longlong
int* ptr2 = (int*)((long long)a + 1)
提醒: X64 - 64位环境下,指针的大小是8个字节 X86 - 32位环境下,指针的大小是4个字节
三.浮点数在内存中的存储
有效数字M的具体存储
指数E的具体存储
四.浮点数读取的过程
正常情况的读取
E全为0
E全为1
例题
int n=9;易得出9的补码补码:00000000000000000000000000001001printf("n的值为:%d\n", n); 易得出结果为90 00000000 00000000000000000001001第一个代表符号 为+00000000 读取结果 1-127=-12600000000000000000001001 读取结果 0.00000000000000000001001答案就是:0.00000000000000000001001*2^(-126)%f默认打印6位小数 结果就是0.000000*pFloat = 9.0;1001.0(-1)^0 * 1.001*2^3S=0M=1.001E=3(以3+127=130的二进制存入)01000001000100000000000000000000printf("num的值为:%d\n", n);的结果就是上面直接读取的结果1091567616printf("*pFloat的值为:%f\n", *pFloat);%f默认打印6位小数就是9.000000
浮点数没有原码反码补码之说只有一个将其存储的码,并且可以直接读取展示