欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

结构体内存对齐与大小端问题

程序员文章站 2022-07-13 22:29:41
...

首先我们先举个例子,试着算一下结构体的大小

class S1
{
	 char _c1;
	 int _i;
	 char _c2;
};
class S2
{
	 char c1;
	 char c2;
	 int i;
};
class S3
{
	 double d;
	 char c;
	 int i;
};
class S4
{
	 char c1;
	 struct S3 s3;
	 double d;
};

结构体内存对齐与大小端问题
是不是和你想的不太一样呢?

我们先来看一下结构体内存对齐的规则:

  1. 第一个成员在与结构体偏移量为0的地址处。

  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
    VS中默认的对齐数为8,gcc中的对齐数为4

  3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。

  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
    结构体内存对齐与大小端问题

  5. 为什么要进行内存对齐
    · 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
    · 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

  6. 如何让结构体按照指定的对齐参数进行对齐?
    · 使用**(# pragma pack())**

# pragma pack(2)   struct d
{
	char a; // 1  
	long  long b; // 8    
	short c; // 2 
};

还有一种方法是在编译器中设置默认参数

  1. 什么是大小端?如何测试某台机器是大端还是小端,有没有遇到过要考虑大小端的场景

大小端概念

小端:低位字节序的内容放在低地址处,高位字节序内容放在高地址处

大端:低位字节序的内容放在高地址处,高位字节序内容放在低地址处
结构体内存对齐与大小端问题
看了这个例子,一定会有这样的疑问:应该是00 00 00 01,为什么会是这样的?
因为这是是小端存储结构体内存对齐与大小端问题
如何测试大小端?
方法一:利用公用体(联合union)(常用)

int Check_sys()
{	
union Un
{		
	char a;	
	int b;
}
	un;	
	un.b = 1;	
return un.a;
}

int main()
{	
	int ret = Check_sys();	
if (1 == ret)	
{		
	printf("当前模式为小端存储\n");	
}
   
else
{		
	printf("当前模式为大端存储\n");
}	
system("pause");	
return 0;}

结构体内存对齐与大小端问题
共用体:共用体是多种数据的覆盖存储,几个不同的成员 变量共占同一段内存空间,而且都是从同一地址开始存储的,只是在任意时刻只存储一种数据,因此分配给共用体的存储区域大小至少要有存储最大一个成员数据类型所占用的存储空间。

用共用体来检测大小端的原理:由于共用体类型采取的是存储覆盖的机制,准许不同的类型数据相互覆盖,是一种同一存储区域由不同类型成员共享的数据类型。
结构体内存对齐与大小端问题
所以我们只要给b赋值为1,如果a的值也为1,那么就是小端,反之就是大端。

方法二:

int main()
{
    int a = 0x12345678;//十六进制值为0x12345678
    char*p=(char*)&a;//强转地址,使得指针p仅可以解引用到一个字节大小的值
    if(p == 0x78)
    {
        printf("小端模式!\n");
    }
    else
    {
        printf("大端模式!\n");  
    }
    return 0;
}