c语言data占多少字节,【转】C语言中的Data Alignment和struct的size

本文深入探讨了C/C++中的数据对齐原则及其对结构体成员的影响。通过实例解析了如何实现有效的内存布局,以确保高效的数据访问。

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

C语言,在对一个 struct variable使用sizeofoperator(操作符)的时候,往往得到的结果并不是我们想象中——struct内所有member的size之和。

当清楚了什么是Data

alignment(数据对齐),对这个问题就豁然开朗了。

Data Alignment

在C/C++,甚至所有programming language中,每个Data object,更确切的说是

每个variable都有两个属性 :

value (自身的值)

memory

address(其内存地址)

对每个variable的分析,都是基于内存分析的。所以,分析variable自身value的时候,又是分析

其在内存中的存储形式.所以更确切的是

Variable

Properties

bit pattern

memory

address

往往variable最重要的属性,是其内存地址。这也是为什么

在C/C++中,指针,pointer是如此的强大。

Data Alignment 并非针对 Data

本身,而是Data(Variable)的内存地址。在

MSDN 对 Alignment做出定义,其第一句话便是

Alignment is a property of a memory address

以一张表格来展现32-bit machine 的内存结构

a4c26d1e5885305701be709a3d33442f.png

计算机中,内存是由大量的,连续的,可寻址的或编了号的memory cells(内存单元)构成。每个memory cell 占1

byte。

假如上述表格 bank0的address

为X,那么bank1,bank2,bank2的地址分别为X+1,X+2,X+2。

CPU在处理内存数据时,并非一次提取一个memory cell,一般提取一组相邻内存单元。在32-bit

machine,CPU一次从内存中读取 4个连续的memory cell(4-byte) 。所以在此表格中,4 byte

chunk(4字节流) 为一个读取周期。在读取一个int型 数据时,仅仅需要一个周期(int 占4

byte)。读取Double型,则需要2个读取周期。表格(D0-D31,32-bit)表示一个内存周期。如果是8-bit

machine

即1字长(D0-D7),则需要4个周期来读取一个integer。

说了一些基本的内存知识,接下来看看

MSDN对Alignment的定义是怎么样的

MSDN 写道

Alignment is a property of a memory address, expressed as the

numeric address modulo a power of 2. For example, the address

0x0001103F modulo 4 is 3; that address is said to be aligned to

4n+3, where 4 indicates the chosen power of 2. The alignment of an

address depends on the chosen power of two. The same address modulo

8 is 7. An address is said to be aligned to X if

its alignment is Xn+0.

CPUs execute instructions that operate on data stored in memory,

and the data are identified by their addresses in

memory.

仔细理解下,可以总结为,当向内存中放入一个数据(variable)时,此数据的地址,严格来说是offset,起始地址,必须是此数据的Alignment的整数倍。即上述

Xn+0。

对于每种类型的数据,都有其自身的Alignment

Data Type

Alignments(in Bytes)

char

1

short

2

int

4

float

4

double

4 or

8

例如char

的offset可以在bank0,bank1,bank2,bank3任意一个(这里为了方便,假设bank0初始位置的address为0,依次类推)。short型的2

bytes只能存储在

bank0-bank1或者bank2-bank3,假如其offset在bank1上,即存储在bank1-bank2,那么此address为奇数,并非short

alinment的整数倍。

int型,offset只能在bank0上,在其他位置,都不会是4的整数倍。如果一个int型的整数,0xABCDEF,在内存中的起始位置在

bank1 上会发生什么呢?

a4c26d1e5885305701be709a3d33442f.png

可以看到此integer的addres并非是4的整数倍,跨过两行,那么在读取此data时,就需要两个读取周期了。

所以data

alignment正是用来处理variable在这些bank中的存储方式。以避免发生此情况。在上表中,此整数的地址为5,5=4n+1,按照MSDN定义来说,此整数的alignment为1.但是int

型的alignment应该是4。所以这种情况又称为misaligned。

Data Structure

Padding

在C/C++中,因为对variable都有alignment的要求,所以在struct中,每一个member都要遵循alignment的要求。就拿

MSDN中的一个例子,来谈下struct的alignment

C代码 a4c26d1e5885305701be709a3d33442f.png

struct x_

{

char a; // 1 byte

int b; // 4 bytes

short c; // 2 bytes

char d; // 1 byte

} MyStruct;

同上述表格一样,struct中的member在内存中,是由下至上allocate的。

char a的起始位置在bank0,假如addrees为0;

int b,是不可以在bank1,bank2,bank3,这样b的offset为奇数,不是4的整数倍,所以只能在bank4,其4

bytes在 bank4-bank5-bank6-bank7;

那么在char a与int b之间需要填补3个无意义的byte。来满足int

b的对齐方式。

short c是可以在bank8的,8为2的整数倍。所以b,c间无需要填补。那么short c 存储在

bank8-bank9。

char d可以存储在任何位置。那么char d 则存储在

byte10.

最后需填补1 byte

padding byte

char

d

short c

short

c

int

b

int b

int b

int b

padding byte

padding byte

padding byte

char a

在最后填补一个byte的原因是:

在struct的member的alignment中,找到alignment的最大值(此处为4

bytes),在struct的最后一个member填补 padding bytes使整个struct的size

为此aligment(4 bytes)的整数倍。

所以上述struct 在内存中的实际形式为

C代码 a4c26d1e5885305701be709a3d33442f.png

// Shows the actual memory layout

struct x_

{

char a; // 1 byte

char _pad0[3]; // padding to put 'b' on 4-byte boundary

int b; // 4 bytes

short c; // 2 bytes

char d; // 1 byte

char _pad1[1]; // padding to make sizeof(x_) multiple of 4

}

此struct的size为12 bytes,而不是8

bytes。

Resource

http://msdn.microsoft.com/en-us/library/ms253949.aspx

http://en.m.wikipedia.org/wiki/Data_structure_alignment#section_5

http://www.geeksforgeeks.org/archives/9705

http://www.songho.ca/misc/alignment/dataalign.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值