sizeof 与结构体大小及结构体对齐问题, 字节对齐

本文探讨了在C语言中结构体字节对齐对文件读写造成的影响。通过一个实例说明了由于结构体内部字段的对齐规则,导致在读写文件时可能产生的错位问题。内容包括结构体每个字段必须在其大小的整数倍位置开始,以及由此引发的数据读取不准确的现象。

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

遇到了这样的情况
有如下结构体
struct ST_1
{
      char a;
      double b;
      char c;
};

 

1. 写入文件

ST_1 st;
st.a = 'a';
st.b = 123.4;
st.c = 'b';
fwrite(&st, sizeof(ST_1), 1, file);
 

2. 从文件中读出来

ST_1 st;
fread(&st.a, sizeof(char), 1, file);
fread(&st.b, sizeof(double), 1, file);
fread(&st.c, sizeof(char), 1, file);
但是这样子读出来的结果是错误的. 而必须这样子读取
fread(&st, sizeof(ST_1), 1, file);

什么原因, 很明显是读取错位了. 什么原因造成错位? 这就是与结构体对齐有关.


看下面例子

struct ST_2
{
      char a;       // 位置在0, 大小是1
      double b;   // 位置在8  大小是8
      char c;      // 位置在16 - 1
};     // 总大小是 24 (sizeof(char) + sizeof(double) + sizeof(char) = 10 != 24
1. 首先, 一个结构体的大小是按照结构体中大小最大的那个字段对齐的.
    例如ST_2 是按照sizoef(double)大小对齐的(也就是8Byte).


2. 每个字段的开始位置都要在其大小的整数倍位置.
    例如: ST_2.b, 大小为8Byte, 但是ST_2.a大小为1Byte, 所以ST_2.b的位置在8, 前面7个Byte就不要了.

#include "stdafx.h"
#include <iostream>

// 默认是以该结构中占最大字节数那个类型大小对齐
// 12
struct ST_0
{
	char a;			// 1
	int b;			// 4
	char c;			// 1
};
// 以结构中最大的那个变量的大小对齐, 这里是4字节对齐
//	|--|--|--|--||--|--|--|--||--|--|--|--|
//	|01|02|03|04||01|02|03|04||01|02|03|04|
//	|--|--|--|--||--|--|--|--||--|--|--|--|
//	|a  00 00 00||b  b  b  b ||c  00 00 00|
//	|--|--|--|--||--|--|--|--||--|--|--|--|

struct ST_0_0
{
	ST_0 a;
	char d;
};
// 以结构中最大的那个变量的大小对齐, 这里是4字节对齐
//	|--|--|--|--||--|--|--|--||--|--|--|--||--|--|--|--|
//	|01|02|03|04||01|02|03|04||01|02|03|04||01|02|03|04|
//	|--|--|--|--||--|--|--|--||--|--|--|--||--|--|--|--|
//	|a  00 00 00||b  b  b  b ||c  00 00 00||d  00 00 00|
//	|--|--|--|--||--|--|--|--||--|--|--|--||--|--|--|--|


// 24
struct ST_1
{
	char a;			// 1
	double b;		// 8
	char c;			// 1
};
// 以结构中最大的那个变量的大小对齐, 这里是8字节对齐
//	|--|--|--|--|--|--|--|--||--|--|--|--|--|--|--|--||--|--|--|--|--|--|--|--|
//	|01|02|03|04|05|06|07|08||01|02|03|04|05|06|07|08||01|02|03|04|05|06|07|08|
//	|--|--|--|--|--|--|--|--||--|--|--|--|--|--|--|--||--|--|--|--|--|--|--|--|
//	|a  00 00 00 00 00 00 00||b  b  b  b  b  b  b  b ||c  00 00 00 00 00 00 00|
//	|--|--|--|--|--|--|--|--||--|--|--|--|--|--|--|--||--|--|--|--|--|--|--|--|

// 16
struct ST_2
{
	double b;		// 8
	char a;			// 1
	char c;			// 1
};
// 以结构中最大的那个变量的大小对齐, 这里是8字节对齐
//	|--|--|--|--|--|--|--|--||--|--|--|--|--|--|--|--|
//	|01|02|03|04|05|06|07|08||01|02|03|04|05|06|07|08|
//	|--|--|--|--|--|--|--|--||--|--|--|--|--|--|--|--|
//	|b  b  b  b  b  b  b  b ||a |c |00|00|00|00|00|00|
//	|--|--|--|--|--|--|--|--||--|--|--|--|--|--|--|--|

// 16
struct ST_3
{
	double b;		// 8
	char a;			// 1
	char c;			// 1
	char d;			// 1
};
// 以结构中最大的那个变量的大小对齐, 这里是8字节对齐
//	|--|--|--|--|--|--|--|--||--|--|--|--|--|--|--|--|
//	|01|02|03|04|05|06|07|08||01|02|03|04|05|06|07|08|
//	|--|--|--|--|--|--|--|--||--|--|--|--|--|--|--|--|
//	|b  b  b  b  b  b  b  b ||a |c |d |00|00|00|00|00|
//	|--|--|--|--|--|--|--|--||--|--|--|--|--|--|--|--|

#pragma pack(1)

// 10
struct ST_4
{
	char a;			// 1
	double b;		// 8
	char c;			// 1
};
// 设置成1字节对齐
//	||--||--||--||--||--||--||--||--||--||--||
//	||01||01||01||01||01||01||01||01||01||01||
//	||--||--||--||--||--||--||--||--||--||--||
//	||a ||b ||b ||b ||b ||b ||b ||b ||b ||c ||
//	||--||--||--||--||--||--||--||--||--||--||

// 10
struct ST_5
{
	double b;		// 8
	char a;			// 1
	char c;			// 1
};
// 设置成1字节对齐
//	||--||--||--||--||--||--||--||--||--||--||
//	||01||01||01||01||01||01||01||01||01||01||
//	||--||--||--||--||--||--||--||--||--||--||
//	||b ||b ||b ||b ||b ||b ||b ||b ||a ||c ||
//	||--||--||--||--||--||--||--||--||--||--||

#pragma pack()

int _tmain(int argc, _TCHAR* argv[])
{
	std::cout << "ST_0 :" << sizeof(ST_0) << std::endl;
	std::cout << "ST_0_0 :" << sizeof(ST_0_0) << std::endl;
	std::cout << "ST_1 :" << sizeof(ST_1) << std::endl;
	std::cout << "ST_2 :" << sizeof(ST_2) << std::endl;
	std::cout << "ST_3 :" << sizeof(ST_3) << std::endl;
	std::cout << "ST_4 :" << sizeof(ST_4) << std::endl;
	std::cout << "ST_5 :" << sizeof(ST_5) << std::endl;
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值