嵌入式C入门——结构体内存对齐模式

知识点回顾

关于找最大公共子串的两种解题方法

结构体的定义(3种)

结构体变量的定义与使用

  • 变量访问结构体成员 .
  • 指针访问结构体成员 ->

结构体内存对齐模式

  • 原则1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
  • 原则2:结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
  • 原则3:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。

默认对齐值

  • Linux 默认#pragma pack(4)
  • window 默认#pragma pack(8)
  • 注:可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是指定的“对齐系数”。

小结:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。


会了关于结构体内存大小的计算,可是为什么系统要对于结构体数据进行内存对齐呢,很明显所占用的空间大小要更多。原因可归纳如下:

1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。


image

首先,cpu的访问粒度为4,也就是一次性可以读取内存中的四个字节内容;当我们不采用内存对齐策略,如果需要访问A中的b元素,cpu需要先取出0 ~ 3四个字节的内容,发现没有读取完,还需要再次读取,一共需要进行两次访问内存的操作;而有了内存对齐,参考左图,可一次性取出4~7四个字节的元素也即是b,这样就只需要进行一次访问内存的操作。所以操作系统这样做的原因也就是所谓的拿空间换时间,提高效率。


建议:虽然操作系统会浪费空间来完成内存对齐,但是我们有了上面的知识可以通过按照数据类型来调整结构体内部的数据的先后顺序来尽量减少内存的消耗;例如我们将下面结构体A中的顺序调整为B,sizeof(A)的结果为12,而sizeof(B)的结果就是8:

struct A
{
    char a;
    int b;
    char c;
};

struct B
{
    char a;
    char c;
    int b;
};
#include <stdio.h>

// 结构体
struct Test
{
	char c1;
	int  a;
	char c2;
};

struct Test1
{
	char c1;
	char c2;
	char c3;
	int  a;
};

struct Test2
{
	char c1;
	short s;
	int  a;
	char c3;
	
	struct Test t1;
	
	int d[20];
};

// 1、结构体的成员的首地址要能被该成员的类型长度整除
// 2、结构体为成员分配空间原则:
//    a、每次分配的时候按当前最大类型分配
//    b、如果当前空间够用,则不再分配空间
//    c、如果当前类型大于系统系数的时候,按系统系数标准进行分配空间,否则按最大类型分配空间

int main()
{
	printf ("sizeof Test = %lu\n", sizeof(struct Test));
	printf ("sizeof Test = %lu\n", sizeof(struct Test1));
	printf ("sizeof Test = %lu\n", sizeof(struct Test2));
	
	struct Test2 t1, t2;
	t1 = t2;
 
	return 0;
}




































猜你喜欢

转载自blog.csdn.net/qq_35599308/article/details/84568617