sizeof(struct)--关于字节对齐的问题

本文通过两个实例探讨了结构体大小及字节对齐问题,解析了不同编译器环境下结构体成员对齐规则,并展示了如何计算结构体的大小。

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

和很多IT新人一样,经常对结构体的 size 搞不太清楚,于是今天花了点儿时间仔细研究了一下,记录如下以便参考。

 

问题1:对如下程序其运行结果是什么?

int main()
{
	typedef struct A{
		bool b;
		int i;
		short s;
		struct{
			bool b;
			double d;
		}B;
		char ca[5];
		double d;
		union{
			char ca[3];
			int i;
		}U;
	}A;

	A a;
	cout << "Sizeof(A)    = " << sizeof(A)    << " \t Addr: " << &a      << endl;
	cout << "Sizeof(A.b)  = " << sizeof(a.b)  << " \t Addr: " << &(a.b)  << endl;
	cout << "Sizeof(A.i)  = " << sizeof(a.i)  << " \t Addr: " << &(a.i)  << endl;
	cout << "Sizeof(A.s)  = " << sizeof(a.s)  << " \t Addr: " << &(a.s)  << endl;
	cout << "Sizeof(A.B)  = " << sizeof(a.B)  << " \t Addr: " << &(a.B)  << endl;
	cout << "Sizeof(A.ca) = " << sizeof(a.ca) << " \t Addr: " << &(a.ca) << endl;
	cout << "Sizeof(A.d)  = " << sizeof(a.d)  << " \t Addr: " << &(a.d)  << endl;
	cout << "Sizeof(A.U)  = " << sizeof(a.U)  << " \t Addr: " << &(a.U)  << endl;
	return 0;
}


 

这里主要涉及到的就是字节对齐问题,先定义一个概念,结构体宽度 = 结构体的最宽 基本类型成员宽度。

字节对齐的细节由具体编译器决定,但一般都满足以下三个规则:

1. 结构体变量的首地址能够被其结构体宽度所整除;

2. 结构体的每个成员相对于结构体首地址的偏移量都是该成员宽度的整数倍,多余的空间被填充;

3. 结构体的总大小为结构体宽度的整数倍,不够的空间将用填充位补齐。

从理论上来说,将结构体的成员一个接一个地放也是可以的,不过将数据存放进行对齐主要是基于CPU在存取效率方面的考虑。

对于第2条的理解可以从本文的两个实例入手,如果该成员是基本数据类型,那么这里的宽度就指其sizeof()返回值,如果该成员也是一个结构体,那么这里的宽度就指其结构体宽度。

以下是问题1的程序在VS2010上编译后Win32系统下运行的结果:

 由此可分析Struct A 的内存映像:

 

 

问题2:对结构体A内的结构体B,其相对于结构体A首地址的偏移量是sizeof(B)的整数倍吗?

int main()
{
	typedef struct A{
		bool b;
		int i;
		short s;
		struct{
			bool b;
			int d;
		}B;
		char ca[5];
		double d;
		union{
			char ca[3];
			int i;
		}U;
	}A;

	A a;
	cout << "Sizeof(A)    = " << sizeof(A)    << " \t Addr: " << &a      << endl;
	cout << "Sizeof(A.b)  = " << sizeof(a.b)  << " \t Addr: " << &(a.b)  << endl;
	cout << "Sizeof(A.i)  = " << sizeof(a.i)  << " \t Addr: " << &(a.i)  << endl;
	cout << "Sizeof(A.s)  = " << sizeof(a.s)  << " \t Addr: " << &(a.s)  << endl;
	cout << "Sizeof(A.B)  = " << sizeof(a.B)  << " \t Addr: " << &(a.B)  << endl;
	cout << "Sizeof(A.ca) = " << sizeof(a.ca) << " \t Addr: " << &(a.ca) << endl;
	cout << "Sizeof(A.d)  = " << sizeof(a.d)  << " \t Addr: " << &(a.d)  << endl;
	cout << "Sizeof(A.U)  = " << sizeof(a.U)  << " \t Addr: " << &(a.U)  << endl;
	return 0;
}

相对于问题1,问题2的程序只是将结构体B第2个成员的类型改成了int,则运行后可以看到如下输出:

其内存映像亦可分析出来:

由此可见,对于第2条规则并不是以成员的大小计算偏移地址,而是以成员的宽度来计算的。此外,对于同样的一些成员,不同的排列顺序也会导致结构体 size 的不同,即编译器是根据成员出现的次序来分配空间的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值