C++结构变量数据对齐问题

为了避免混淆。做例如以下规定,下面代码若不加特殊说明都执行于32位平台,结构体的默认对齐值是8,各数据类型所占字节数分别为

char占一个字节

int占四个字节

double占八个字节。

两个样例

请问以下的结构体大小是多少?

struct Test
{
    char c ;
    int i ;
};

这个呢?

struct Test1
{
    int i ;
    double d ;
    char c ;
};

在发布答案之前先看一下对齐的规则。

对齐规则

一般来说,结构体的对齐规则是先按数据类型自身进行对齐,然后再按整个结构体进行对齐。对齐值必须是2的幂。比方1,2。 4, 8。 16。

假设一个类型按n字节对齐,那么该类型的变量起始地址必须是n的倍数。

比方int按四字节对齐,那么int类型的变量起始地址一定是4的倍数。比方0x0012ff60。0x0012ff48等。

数据自身的对齐

数据自身的对齐值通常就是数据类型所占的空间大小。比方int类型占四个字节,那么它的对齐值就是4

整个结构体的对齐

整个结构体的对齐值通常是结构体中最大数据类型所占的空间,比方以下这个结构体的对齐值就是8,由于double类型占8个字节。

struct Test2
{
    int i ;
    double d ;
};

样例答案

有了上面的基础。再回过头去看看一開始的两个样例

先看结构体Test

1 c是char类型,按1个字节对齐

2 i是int类型。按四个字节对齐。所以在c和i之间实际上空了三个字节。

整个结构体一共是1 + 3(补齐)+ 4 = 8字节。

再看Test1

i是int类型。按4字节对齐

d是double类型,按8字节对齐,所以i和d之间空了4字节

c是char类型。按1字节对齐。

所以整个结构体是 4(i) + 4(补齐)+ 8(d) + 1(c) =  17字节。注意!还没完,整个结构体还没有对齐。由于结构体中空间最大的类型是double。所以整个结构体按8字节对齐,那么终于结果就是17 + 7(补齐) = 24字节。

书写结构体的建议

我们对Test1做一点修改

struct Test1
{
    char c ;
    int i ;
    double d ;
};

这时Test1的大小就变成了16,而不是24了,节省了8个字节!

可见结构体中成员的书写顺序对结构体大小的影响还是非常大的。一个好的建议是,依照数据类型由小到大的顺序进行书写。

怎样改动结构体的对齐值

使用预处理指令

#pragma pack(num)

num是结构体的对齐值,比方以下的样例按四个字节对齐。

#pragma pack(4)

怎样查看结构体的对齐值

使用预处理命令

#pragma pack(show)

该命令来查看当前的对齐值,可是要注意的是,结果是以warning的形式输出的,所以要在VS的警告窗体中才看得见。例如以下

warning C4810: value of pragma pack(show) == 8

时间: 2024-08-01 22:36:37

C++结构变量数据对齐问题的相关文章

C语言结构体变量字节对齐问题总结

结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列, 而不是简单地顺序排列,这就是内存对齐. 内存对齐的原因: 1)某些平台只能在特定的地址处访问特定类型的数据: 2)提高存取数据的速度.比如有的平台每次都是从偶地址处读取数据,对于一个int型的

【转】彻底搞清计算结构体大小和数据对齐原则

彻底搞清计算结构体大小和数据对齐原则 数据对齐: 许多计算机系统对基本数据类型合法地址做出了一些限制,要求某种类型对象的地址必须是 某个值K(通常是2,4或8)的倍数.这种对齐限制简化了形成处理器和存储器系统之间的接口的硬件 设计.例如,假设一个处理器总是从存储器中取出8个字节,则地址必须为8的倍数.如果我们能保 证将所有的double类型数据的地址对齐成8的倍数,那么就可以用一个存储器操作来读或者写值了. 否则,我们可能需要执行两次存储器访问,因为对象可能被分放在两个8字节存储块中. 当数据类

结构体字节对齐

结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列, 而不是简单地顺序排列,这就是内存对齐. 内存对齐的原因: 1)某些平台只能在特定的地址处访问特定类型的数据: 2)提高存取数据的速度.比如有的平台每次都是从偶地址处读取数据,对于一个int型的

【APUE】Chapter17 Advanced IPC & sign extension & 结构体内存对齐

17.1 Introduction 这一章主要讲了UNIX Domain Sockets这样的进程间通讯方式,并列举了具体的几个例子. 17.2 UNIX Domain Sockets 这是一种特殊socket类型,主要用于高效的IPC,特点主要在于高效(因为省去了很多与数据无关的格式的要求). int socketpair(int domain, int type, int protocol, int sockfd[2]) 这个函数用于构建一对unix domain sockets:并且与之前

数据对齐总结

必须注意:对齐是多少字节对齐,不是多少位对齐. 对齐原因: 如上图片,内存一般是四个单位一列,CPU在读取内存数据的时候,通过总线并行读取每个单位的数据.对于CPU 32bit的寄存器而言. 0-7bit是来自于内存芯片0的位 8-15bit是来自内存芯片1的位 16-23bit是来自芯片2 24-31来自芯片3 而内存结构是,内存地址一个单位也就是基本单位是1字节,也就是8位二进制数. 在读取数据的时候实际上是0-7位从芯片0读取,8到15位从芯片2读取,以此类推. 所以读取一个4字节数据,是

内存中的数据对齐

数据对齐,是指数据所在的内存地址必须是该数据长度的整数倍.DWORD数据的内存起始地址能被4除尽,WORD数据的内存起始地址能被2除尽.x86 CPU能直接访问对齐的数据,当它试图访问一个未对齐的数据时,会在内部进行一系列的调整.这些调整对于程序来说是透明的,但是会降低运行速度,所以编译器在编译程序时会尽量保证数据对齐.同样一段代码,我们来看看用VC.Dev C++和LCC这3个不同的编译器编译出来的程序的执行结果: 这是用VC编译后的执行结果: 变量在内存中的顺序:b(1字节)-a(4字节)-

C++ Primer 学习笔记_15_从C到C++(1)--bool类型、const限定符、const与#define、结构体内存对齐

欢迎大家阅读参考,如有错误或疑问请留言纠正,谢谢 一.bool类型(C语言没有) 1.逻辑型也称布尔型,其取值为true(逻辑真)和false(逻辑假),存储字节数在不同编译系统中可能有所不同,VC++中为1个字节. 2.声明方式:bool result; result=true; 3.可以当作整数用(true一般为1,false为0) 4.把其它类型的值转换为布尔值时,非零值转换为true,零值转换为false 5.示例 #include <iostream> using namespace

C/C++数据对齐汇总

C/C++数据对齐汇总 这里用两句话总结数据对齐的原则: (1)对于n字节的元素(n=2,4,8,...),它的首地址能被n整除,才干获得最好的性能: (2)如果len为结构体中长度最长的变量,size为CPU(处理器)的位数,对齐规则: 若len < size,则以len为单位对齐 若len >= size,则以size为单位对齐 这里不考虑指定对齐方式的情况. 測试 struct B{ bool i; int j; bool k; }; struct A{ int j; bool i; b

数据对齐与代码优化笔记

1. 一直以来对数据对齐都不明白,直到看了这篇文章后才能说是有点感觉,结合代码将理解写下来,以备将来回头加深理解或者是修正错误的认知. http://www.searchtb.com/2013/04/performance_optimization_tips.html 代码如下,运行的环境是64位的linux机器,内核3.10,gcc 4.8.2 /*************************************************************************