struc 字节对齐

本文探讨了C语言中结构体的内存对齐规则及其如何影响结构体的大小。通过不同类型的结构体示例,展示了如何使用__attribute__((packed))来实现紧凑存储,避免不必要的内存浪费,并提供了一个具体的代码实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

总结:
1、结构体对齐过程中以最大类型对齐,结构体大小是其倍数。
2、__attribute__((packed)) 改变其对齐方式为紧凑方式

3、如果有__attribute__((packed)) struct嵌套使用,则每个结构都要使用__attribute__((packed)),遇到一个问题:在没有都使用__attribute__的时候,保存文件之后,下次读取出来的数据丢失了。  


#include<stdio.h>
#include<string.h>


#define _PACKED __attribute__((packed))
struct a
{
	char a;
	int b;
	char c;
	char d[10];
};

struct b
{	
	int b;
	char a;
	char c;
	char d[10];
};


struct c
{	
	char a;
	char c;
	int b;
	char d[10];
};

struct d
{	
	char a;
	char c;
	int b;
	char d[10];
}_PACKED;


struct e
{	
	char a;
	char c;
	int b;
	char d[10];
	struct c eec;
	char e;
}_PACKED;

int main()
{
	int i;
	struct a a;
	struct b b;
	struct c c;
	struct d d;
	struct e e;

	c.a = 'a';
	c.b = 20;
	c.c = 'c';
	c.d[0] = 'd';
	c.d[1] = c.d[0]+1;
	c.d[2] = c.d[0]+2;
	c.d[3] = c.d[0]+3;
	c.d[4] = c.d[0]+4;
	c.d[5] = c.d[0]+5;
	c.d[6] = c.d[0]+6;
	c.d[7] = c.d[0]+7;
	c.d[8] = c.d[0]+8;
	c.d[9] = c.d[0]+9;

	e.a = 'A';
	e.c = 'C';
	e.b = 20;
	memcpy(e.d,c.d,sizeof(e.d));
	memcpy(&e.eec,&c,sizeof(struct c));
	e.e= 'E';
	
	printf("a:	a=%p b=%p c=%p\n",&(a.a),&(a.b),&(a.c));
	for(i=0;i<10;i++)
	{
		printf("%p ",&(a.d[i]));
	}
	printf("\n");

	printf("b:	a=%p b=%p c=%p\n",&(b.a),&(b.b),&(b.c));
	for(i=0;i<10;i++)
	{
		printf("%p ",&(b.d[i]));
	}
	printf("\n");

	printf("c:	a=%p b=%p c=%p\n",&(c.a),&(c.b),&(c.c));
	for(i=0;i<10;i++)
	{
		printf("%p ",&(c.d[i]));
	}
	printf("\n");

	printf("d:	a=%p b=%p c=%p\n",&(d.a),&(d.b),&(d.c));
	for(i=0;i<10;i++)
	{
		printf("%p ",&(d.d[i]));
	}
	printf("\n");

	printf("e:	a=%c b=%d c=%c\n",e.a,e.b,e.c);
	for(i=0;i<10;i++)
	{
		printf("%c ",e.d[i]);
	}
	printf("\n");	
	printf("\nSIZE:%d %d %d %d %d\n",sizeof(struct a),sizeof(struct b),sizeof(struct c),sizeof(struct d),sizeof(struct e));
	void *p;
	p=&e;
	FILE* fp = fopen("e.txt","wr");
	fwrite(p,sizeof(struct e),1,fp);
	fclose(fp);

	fp = fopen("c.txt","wr");
	p=&c;
	fwrite(p,sizeof(struct c),1,fp);
	fclose(fp);	
	return 0;
}


### x86汇编指令集代码示例 #### 基本栈操作 在x86架构中,`push` 指令用于将数据压入堆栈。该指令会先减去ESP寄存器中的值(因为x86堆栈向下增长),再把操作数存储到由ESP指向的新位置[^3]。 ```assembly section .data ; 数据段定义 section .bss ; 未初始化的数据声明 section .text global _start _start: mov eax, 1 ; 将立即数1移动到eax寄存器 push eax ; 把eax的内容推送到堆栈上 ``` #### 结构体内存布局调整 当编写涉及结构体或类的程序时,编译器通常按照指定的方式布置这些对象在内存中的排列方式。然而,在某些情况下为了保持自然边界对齐,可能会增加填充字节。对于x86处理器而言,这种对齐通常是4字节或8字节宽度[^2]。 ```c struct Example { char c; /* 占用1个字节 */ int n; /* 需要额外3个字节作为填充以达到4字节对齐 */ }; ``` 转换成对应的汇编表示形式: ```assembly Example_struc: db ? ; 字符变量 'c' dd ? ; 整型变量'n'加上必要的填充 ``` #### 复杂指令实例 复杂指令如字符串复制命令可以在单条指令内完成多个动作,这类指令往往通过微码实现其功能。例如,`movs` 可以用来高效地处理字符串传输任务[^1]。 ```assembly section .data source db "Hello", 0 ; 定义源串 dest times 6 db 0 ; 初始化目标缓冲区大小为6字节并清零 section .text lea esi, [source] ; 加载有效地址至ESI(源指针) lea edi, [dest] ; 加载有效地址至EDI(目的指针) mov ecx, 6 ; 设置循环计数器ECX=6 rep movsb ; 使用重复前缀执行多次单字节传送 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值