一、数据在内存中的存储
1、基本数据范例存储
- 整型:如int范例,通常在32位体系中占4个字节,在内存中以二进制补码的情势存储。比方,整数10的二进制表示为00000000 00000000 00000000 00001010,以小端字节序存储时,在内存中的次序是0A 00 00 00;以大端字节序存储时,次序是00 00 00 0A。
- 浮点型:单精度float范例一样平常占4个字节,双精度double范例占8个字节。浮点数在内存中的存储遵照IEEE 754标准,以符号位、指数位和尾数位的情势存储。比方,单精度浮点数3.14在内存中的存储情势与整数完全不同。
- 字符型:char范例通常占1个字节,用来存储单个字符的ASCII码值。比方,字符'A'的ASCII码值是65,在内存中存储为41(十六进制)。
- int main()
- {
- printf("%zd\n", sizeof(int));
- printf("%zd\n", sizeof(char));
- printf("%zd\n", sizeof(float));
- return 0;
- }
复制代码
2、数组存储
- 数组中的元素在内存中是连续存储的。比方,int arr[5] = {1, 2, 3, 4, 5};,数组arr的5个元素在内存中依次排列,假设数组首地点为0x1000,那么arr[0]存储在0x1000处,arr[1]存储在0x1004处,以此类推,每个元素之间的偏移量为sizeof(int)。
3、布局体存储
1、基本存储规则
- 布局体的成员在内存中是按照定义的次序依次存储的。每个成员的存储地点相对于布局体首地点有肯定的偏移量。比方,对于布局体struct Example { int a; char b; };,起首存储int型成员a,然后存储char型成员b。
- 编译器大概会在布局体成员之间插入填充字节(Padding),这是为了满足成员的对齐要求。对齐要求通常是为了提高内存访问的服从,因为大多数盘算机硬件在访问内存时,对于按照肯定字节对齐的数据访问速率更快。比方,在32位体系中,int范例通常要求4字节对齐,double范例要求8字节对齐等。
2、举例阐明
- 例1:简单布局体
- 考虑布局体struct Simple { char c; int i; };。假设char范例占1个字节,int范例占4个字节。
- 起首存储c,其地点假设为布局体首地点0x0000,占1个字节,存储范围是0x0000。
- 由于int范例要求4字节对齐,在c和i之间会插入3个填充字节。i的存储起始地点为0x0004,占4个字节,存储范围是0x0004 - 0x0007。所以整个布局体Simple占8个字节。
- 例2:包含数组的布局体
- 定义布局体struct ArrayStruct { int a; char arr[3]; int b; };。
- 起首存储a,假设其地点为0x0000,占4个字节,存储范围是0x0000 - 0x0003。
- 接着存储arr数组,其起始地点为0x0004,因为char数组本身没有对齐要求,且前面a已经保证了4字节对齐。arr占3个字节,存储范围是0x0004 - 0x0006。
- 对于b,由于int范例要求4字节对齐,所以在arr和b之间会插入1个填充字节。b的存储起始地点为0x0008,占4个字节,存储范围是0x0008 - 0x000B。整个布局体ArrayStruct占12个字节。
- 例3:嵌套布局体
- 定义布局体struct Inner { char c; };和struct Outer { int a; struct Inner in; char b; };。
- 起首存储Outer布局体中的a,假设其地点为0x0000,占4个字节,存储范围是0x0000 - 0x0003。
- 接着存储Inner布局体中的c,由于Inner布局体是嵌套在Outer布局体中的,c的存储起始地点为0x0004,占1个字节,存储范围是0x0004。
- 对于Outer布局体中的b,因为char范例前面已经满足了4字节对齐(由于a的存储),所以b的存储起始地点为0x0005,占1个字节,存储范围是0x0005。整个Outer布局体占8个字节。
3、检察布局体巨细和成员偏移量的方法
- 在C语言中,可以使用sizeof运算符来检察布局体的巨细。比方,对于上述struct Simple布局体,可以通过printf("%d", sizeof(struct Simple));来输出布局体的巨细。
- 有些编译器提供了扩展来检察布局体成员的偏移量,如在GCC中,可以使用__attribute__((packed))来取消布局体的对齐填充,使得布局体按照紧密排列的方式存储,这样可以更清楚地看到成员的原始偏移量。不外这种方式大概会影响内存访问服从,一样平常用于特殊的需求,如数据存储格式有严格要求的网络协议数据包的构建等。
二、巨细端字节序
- 概念:
- 大端字节序(Big-Endian):也叫大端序或大字节序,数据的高位字节存于低地点,低位字节存于高地点。比方,对于整数0x12345678,高位字节0x12存于内存低地点,接着依次是0x34、0x56、0x78存于更高地点,就像按从左到右(高位在前)的次序存储。
- 小端字节序(Little-Endian):又称小端序或小字节序,与大端字节序相反,数据的低位字节存于低地点,高位字节存于高地点。对于0x12345678,在小端字节序下,0x78存于内存低地点,接着是0x56、0x34、0x12存于更高地点,如同从右到左(低位在前)存储。
- 影响:不同的字节序在多字节数据的存储和传输中会产生影响。在网络编程中,通常规定使用大端字节序举行数据传输,以保证不同主机之间数据的一致性。假如两台主机的字节序不同,在举行数据通讯时就必要举行字节序的转换。
三、字节序的判断
- 利用指针范例转换判断:通过将一个多字节数据的地点转换为char *范例指针,然后访问该指针指向的字节,根据第一个字节的值来判断字节序。比方:
- #include <stdio.h>
- int main() {
- int num = 1;
- char *ptr = (char *)#
- if (*ptr == 1) {
- printf("小端字节序\n");
- } else {
- printf("大端字节序\n");
- }
- return 0;
- }
复制代码
- 利用联合体判断:联合体的所有成员共用同一块内存空间,可以利用这一特性来判断字节序。比方:
- #include <stdio.h>
- union EndianTest {
- int num;
- char bytes[4];
- };
- int main() {
- union EndianTest test;
- test.num = 1;
- if (test.bytes[0] == 1) {
- printf("小端字节序\n");
- } else {
- printf("大端字节序\n");
- }
- return 0;
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |