目录
一.整数在内存中的存储
1.1原码,反码和补码
(1)原码
原码是最直观的二进制表示方法,它直接反映了数的正负。对于正数,其原码就是该数的二进制表示(即符号位为0,其余各位为该数的绝对值二进制表示);对于负数,其原码则是符号位为1,其余各位为该数绝对值的二进制表示取反。
示例:
+5的原码:0101
(二进制)
-5的原码(按照直接定义):1101
(注意,这里的1101并不是-5的绝对值4的二进制表示取反,而是直接表示-5)
(2)反码
反码是在原码的基础上,对于负数,将其符号位以外的所有位取反(即0变1,1变0)得到的。正数的反码就是其原码。
示例:
+5的反码:0101
(与原码相同)
-5的原码(按上述定义):1101
,其反码为1010
(仅对符号位以外的位取反)
(3)补码
补码是在反码的基础上加1得到的。补码是计算机中用于表示有符号整数的一种最常用的编码方式,因为它能够简化计算机中的加减法运算(尤其是涉及负数的运算)。补码的正数表示与原码和反码相同,而负数的补码则是其反码加1。
示例:
+5的补码:0101
(与原码、反码相同)
-5的反码为1010
(基于上面的反码示例),其补码为1011
(反码加1)
总结
原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。
反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
补码:反码+1就得到补码。
补码的使用是现代计算机体系结构的基石之一,它使得计算机在处理有符号整数时更加高效和一致。
1.2 存储方式
整型数据:整型数据(如int
、short
、long
等)在内存中通常以二进制补码的形式存储。补码是一种表示有符号整数的方式,可以高效地处理正负数的加减运算。
浮点型数据:浮点型数据(如float
、double
)的存储遵循IEEE 754标准,包含符号位、指数部分和尾数部分。
字符型数据:字符型数据(如char
)在内存中通常以ASCII码或Unicode码的形式存储。
结构体和联合体:结构体(struct
)和联合体(union
)是复合数据类型,它们在内存中的存储方式取决于其成员的类型和顺序。结构体成员在内存中连续存储,而联合体在同一内存位置存储其最大成员的值。
指针:指针变量存储的是内存地址,即指向另一个变量的值。指针的大小取决于操作系统和编译器,通常是4字节(32位系统)或8字节(64位系统)。
二.大小端字节序和字节序判断
2.1 大小端字节序的概念
其实超过⼀个字节的数据在内存中存储的时候,就有存储顺序的问题,按照不同的存储顺序,我们分为大端字节序存储和小端字节序存储,下面是具体的概念:
大端(存储)模式: 是指数据的低位字节内容保存在内存的高地址处,而数据的高位字节内容,保存在内存的低地址处。
小端(存储)模式: 是指数据的低位字节内容保存在内存的低地址处,而数据的高位字节内容,保存在内存的高地址处。
2.2 字节序判断
下面我们通过两段代码来实现字节序的判断
代码1
在这端代码中,我们通过函数check_sys来实现大小端字节序的判断。
check_sys函数通过将一个整型变量i
的地址转换为字符型指针,并访问该指针指向的内存位置(即整型变量的第一个字节),来判断系统的字节序。如果返回的是1
,说明系统的字节序是小端(因为最低有效字节存储在最低的内存地址上);如果返回的不是1
,则理论上表示系统是大端。简而言之,它利用整型变量在内存中的存储方式来检测系统的字节序。
代码2
定义一个联合体(union),该联合体包含两个成员:一个整型(int
)成员i
和一个字符型(char
)成员c
。由于联合体的特性,这两个成员共享同一块内存空间。因此,当给整型成员i
赋值时,实际上也是在修改这块共享内存的内容。
将整型成员i
初始化为1
(在二进制中表示为0000 0001
,这里假设int
类型至少占用多个字节,通常是4字节,但只关注最低有效字节)。由于整型和字符型共享内存,且字符型只占用这块内存的最低有效字节(假设是小端系统),因此字符型成员c
将直接反映出整型成员i
的最低有效字节的值。
然后,函数返回字符型成员c
的值。如果返回的值是1
,那么说明整型成员i
的最低有效字节(即1
)存储在最低的内存地址上,这符合小端字节序的特征。如果返回的值不是1,
表示整型成员i
的最低有效字节没有存储在最低的内存地址上,即系统是大端字节序。
三.练习
练习1
char
和signed char
:由于它们都能存储有符号的整数值,包括-1
,因此当赋值为-1
时,它们能够直接存储并显示-1
。
unsigned char
:由于它不能存储负值,当尝试将-1
赋值给它时,-1
被隐式转换为无符号数255
(因为-1
的二进制补码表示在转换为无符号数时等于255
的二进制表示),因此显示结果为255
。
练习2
char a = -128;
将负值赋给char
,char
是signed
的。
使用printf("%u\n", a);
时,a
首先被提升为int
(或更大整数类型),但%u
要求无符号解释。
-128
的二进制补码在int
中表示时,高位(符号位)为1,在无符号解释下,这些位表示大数值。
因此,-128
的二进制补码在无符号解释下转换为十进制数4294967168
(在32位系统上)。
练习3
char a = 128
使用printf("%u\n", a);
时,a
首先被提升为int
(或更大整数类型),但%u
要求无符号解释。
128
的二进制补码在int
中表示时,高位(符号位)为1,在无符号解释下,这些位表示大数值。
因此,128
的二进制补码在无符号解释下转换为十进制数4294967168
(在32位系统上)。
练习4
char 类型的数组中,数字在内存中的存储:
strlen 函数找到\0后就会停止,\0的ASCII值为0,则从 -1 -2 -3 …… -128 127 126 …… 1的字符串长度是127 + 128 = 255 ,从而输出为255。
练习5
在这道练习中,我们知道unsigned char 的范围是0到255,i<=255恒成立,则该程序死循环
无符号整形>=0,循环判断条件恒成立,程序死循环。
练习6
下面我们画图来进行说明
后记
共勉共勉!!!
喜欢的小伙伴点点赞,点点关注哈,谢谢各位大佬!!