参考

百度百科内存对齐

对齐作用

可以使得以最少的次数将操作数加载到寄存器中,如果数据没有对齐,则当CPU以最小读取数据大小从内存读入数据时可能只取到了一部分数据,而对齐情况下可以一次读入。

对齐修改

在程序中可以通过pragma pack(x)指定对齐大小,x即为需要指定的对齐大小。默认情况下32位平台采用4字节对齐,64位平台采用8字节对齐

对齐规则

摘自百科,感觉概括的比较好。

规则一:成员对齐

数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

#include <stdio.h>

struct A {
char a;
int b;
long c;
}; #define OFFSET(a, b) (int)((char*)&(a.b) - (char*)&a) int main()
{
struct A x;
printf("sizeof %u\n", (int)sizeof(x));
printf("offset a: %u, offset b: %u, offset c: %u\n", OFFSET(x, a), OFFSET(x, b), OFFSET(x, c));
return 0;
}

在64位平台上编译运行输出入:

sizeof 16
offset a: 0, offset b: 4, offset c: 8

内存中的结构体数据分布如下:

  • char类型成员a位于结构体第一个位置,offset为0,占用1-byte空间
  • int类型成员b位于结构体第二位置,offset需要根据类型大小和当前对齐大小决定,sizeof(int) = 4, 而64位默认以8字节对齐,取两者小的,即按4字节对齐,从成员a后找到第一个能被4整除的位置,即offset=4
  • long类型成员需要按8字节对齐,而此时b成员后的offset刚好为8,满足要求直接将成员c放置在成员b后即可。

如果有以下结构体:

struct A {
char a;
int b;
char c;
long d;
};

则在64位平台下其(sizeof(struct A))大小为24 bytes,成员分布如下

可以看到由于char类型成员c的存在,使得long类型成员前需要有大量空白空间才能满足对齐要求,浪费了比较多的空间。如果将成员b和c调换顺序则,只需要16-bytes内存空间。

规则二:结构体补齐

结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

即像如下的结构体:

struct A {
int a;
char b;
};

虽然成员b后面没有再有其他成员用不上规则一,但是仍然需要应用结构体末尾的补齐规则。这个结构体中最大宽度的成员为int型大小小于64位默认对齐大小,所以按4字节补齐,其成员分布如下:



64位环境下其sizeof结果为8

推论

结合1、2可推断:当#pragma pack(n)的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。

空间分配对齐

由于结构体中的起始成员的偏移都是0,所以结构体是否真的对齐并达到性能优化除了结构体内部成员的这些对齐规则,还取决于结构体在内存中的起始位置。如果将结构体分配到一个奇数地址上,那么成员内部做的这些对齐工作都白费了。所以结构体变量都会被对齐到特定的地址。这个特定地址是结构体最宽数据类型大小和pack值的较小者的整数倍。

结构体嵌套

当出现结构体嵌套时,内部的结构体按照其中最长宽度类型长度和pack值的较小者对齐(这跟空间分配时的对齐非常像)。如

struct Inner {
char xa;
int xb;
}; struct A {
char a;
struct Inner b;
}; #define OFFSET(a, b) (int)((char*)&(a.b) - (char*)&a) int main()
{
struct A x;
printf("sizeof %u\n", (int)sizeof(x));
printf("offset a: %u, offset b: %u\n", OFFSET(x, a), OFFSET(x, b));
return 0;
}

64位环境下输出如下:

sizeof 12
offset a: 0, offset b: 4

当将Inner结构体中的xb成员换成long类型时

struct Inner {
char xa;
long xb;
}; struct A {
char a;
struct Inner b;
};

64位平台输出如下:

sizeof 24
offset a: 0, offset b: 8

当通过#pragma pack(4)指定默认对齐大小为4时,情况又会发生变化

#pragma pack(4)
struct Inner {
char xa;
long xb;
}; struct A {
char a;
struct Inner b;
};

64位平台输出结果为:

sizeof 16
offset a: 0, offset b: 4

C 中结构体对齐的更多相关文章

  1. C语言中结构体对齐问题

    C语言中结构体对齐问题 收藏 关于C语言中的结构体对齐问题 1,比如: struct{short a1;short a2;short a3;}A;struct{long a1;short a2;}B; ...

  2. linux中结构体对齐【转】

    转自:https://blog.csdn.net/suifengpiao_2011/article/details/47260085 linux中定义对齐字节 typedef struct  sdk_ ...

  3. C语言结构体对齐

    1.结构体变量中的元素如何访问? (1)数组中元素的访问方式:表面上有2种方式(数组下标方式和指针方式):实质上都是指针方式访问.(2)结构体变量中的元素访问方式:只有一种,用.或者->的方式来 ...

  4. C语言中结构体赋值问题的讨论

    今天帮师姐调一个程序的BUG,师姐的程序中有个结构体直接赋值的语句,在我印象中结构体好像是不能直接赋值的,正如数组不能直接赋值那样,我怀疑这个地方有问题,但最后证明并不是这个问题.那么就总结一下C语言 ...

  5. 解析C语言结构体对齐(内存对齐问题)

    C语言结构体对齐也是老生常谈的话题了.基本上是面试题的必考题.内容虽然很基础,但一不小心就会弄错.写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的 ...

  6. 函数定义从零开始学C++之从C到C++(一):const与#define、结构体对齐、函数重载name mangling、new/delete 等

    今天一直在学习函数定义之类的问题,下午正好有机会和大家共享一下. 一.bool 类型 逻辑型也称布尔型,其取值为true(逻辑真)和false(逻辑假),存储字节数在不同编译系统中可能有所不同,VC+ ...

  7. C语言基础--结构体对齐,位域,联合体

    结构体对齐 1--结构体对齐的原因与意义 许多计算机系统对基本数据类型的可允许地址做出了一些限制,要求某种类型的对象的地址必须是某个值K(通常是2,4,8)的倍数,而这个k则被称为该数据类型的对齐模数 ...

  8. C语言中结构体赋值问题的讨论(转载)

    今天帮师姐调一个程序的BUG,师姐的程序中有个结构体直接赋值的语句,在我印象中结构体好像是不能直接赋值的,正如数组不能直接赋值那样,我怀疑这个地方有问题,但最后证明并不是这个问题.那么就总结一下C语言 ...

  9. 4-17疑难点 c语言之【结构体对齐】

    今天学习了结构体这一章节,了解到了结构体在分配内存的时候采取的是对齐的方式 例如: #include<stdio.h> struct test1 { int a; char b; shor ...

随机推荐

  1. cad.net的undo返回操作

    这是提供给许多从lisp转移到c#的开发人员的一个函数,这个函数利用后绑代码实现undo返回操作. 本代码由edata提供: edata博客 /// <summary> /// 命令动作编 ...

  2. Synchronzied(内置锁)

    原文地址:深入JVM锁机制1-synchronized 1. 线程的状态与转换 当多个线程同时请求某个对象监视器时,对象监视器会设置几种状态用来区分请求的线程: Contention List:所有请 ...

  3. 冰与火之歌居然是在 DOS 系统上写出来的

    简评:<权力的游戏>第八季(最终季)终于开播了!这部美剧的原著小说有一个很有趣的冷知识 -- 它是在运行 DOS 系统的计算机上写出来的.其实不少老粉都已经知道这个典故,不过听到老爷子的亲 ...

  4. 1-1 Vue的介绍

    简单介绍Vue Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视图层,不仅易 ...

  5. oracle跨平台数据迁移 expdp/impdp 字符集问题 导致ORA-02374 ORA-12899 ORA-02372

    环境描述: 源数据库环境:     操作系统:Windows SERVER 2008R2     数据库版本:单实例 ORACLE 11.2.0.1 目标端数据库环境:     操作系统:redhat ...

  6. linux 备忘记录

    杂项记录 Ubuntu 通过/etc/network/interfaces修改IP,重启网络服务貌似也不会生效.可以重启电脑使其生效,或执行: ip addr flush dev ens33 & ...

  7. (转)Linux 系统监控、诊断工具之 top命令详解

    原文:https://www.linuxidc.com/Linux/2014-12/110563.htm 目录 (1)系统.任务统计信息:(2)进程. cpu 统计信息:(3)最后两行为内存信息:3. ...

  8. Python:高效计算大文件中的最长行的长度

    在操作某个很多进程都要频繁用到的大文件的时候,应该尽早释放文件资源(f.close()) 前2种方法主要用到了列表解析,性能稍差,而最后一种使用的时候生成器表达式,相比列表解析,更省内存 列表解析和生 ...

  9. 如何查看第三方apk的信息

    很多时候,我们需要获取别人的apk的信息.但是我们看不到apk的代码,对于apk的信息并没有直接的方法获取.那么,我们要怎么获取apk信息呢? 这里,我整理了两个方法,亲测可用. 第一种,直接使用An ...

  10. Solidity的自定义结构体深入详解

    一.结构体定义 结构体,Solidity中的自定义类型.我们可以使用Solidity的关键字struct来进行自定义.结构体内可以包含字符串,整型等基本数据类型,以及数组,映射,结构体等复杂类型.数组 ...