参考

百度百科内存对齐

对齐作用

可以使得以最少的次数将操作数加载到寄存器中,如果数据没有对齐,则当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. Windows Service 项目中 Entity Framework 无法加载的问题

    Windows Service 项目引用了别的类库项目,别的项目用到了 Entity Framework(通过Nuget引入),但是我的 Windows Service 无法开启,于是我修改了 App ...

  2. iOS 数据持久化-- FMDB

    一.简介 1.什么是FMDB FMDB是iOS平台的SQLite数据库框架 FMDB以OC的方式封装了SQLite的C语言API 2.FMDB的优点 使用起来更加面向对象,省去了很多麻烦.冗余的C语言 ...

  3. Eclipse个人规范化设置

    为保证在各个在各个系统中获得的代码样式保持一致,规范法化开发,对Eclipse进行一些常用通用设置: 1. 代码块缩进 4个空格,如果使用 tab缩进,请设置成 1个 tab为 4个空格.(阿里巴巴开 ...

  4. (转) lsof 一切皆文件

    原文:https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/lsof.html lsof(list open files)是一个查看当前系统文 ...

  5. 【VC版】如何获取其他进程中ListView控件中的内容

    如果需要C#版的,可以看下我之前写的:C#如何获取其他程序ListView控件中的内容 获取其他进程的数据需要使用到以下几个函数: VirtualAllocEx() VirtualFreeEx() W ...

  6. Prototype原型模式(创建型模式)

    1.原型模式解决的问题 现在有一个抽象的游戏设施建造系统,负责构建一个现代风格和古典风格的房屋和道路. 前提:抽象变化较慢,实现变化较快(不稳定) 整个抽象的游戏设施建造系统相对变化较慢,本例中只有一 ...

  7. redis的高级事务CAS(乐观锁)

    Optimistic locking using check-and-set(乐观锁) 乐观锁介绍:watch指令在redis事物中提供了CAS的行为.为了检测被watch的keys在是否有多个cli ...

  8. 有意思的App

    掘金 javadoop 专业相机也羡慕奖 – Focos 说个睡前故事 so easy 奖 – 洪恩双语绘本 效率蹭蹭上升奖 – Sorted³ 时光隧道走一回奖 – NOMO 相机 设计师也爱用奖 ...

  9. Node.js 安装及环境配置之 Windows 篇

    一.安装环境 1.本机系统:Windows 10 企业版(64位)2.Node.js:node-v8.9.4-x64.msi(64位) 二.安装Node.js步骤 1.下载对应自己系统对应的 Node ...

  10. a no-risk path to IEEE P1687

    You’ve heard all about IJTAG (IEEE P1687) [1,2,3], a new standard for accessing embedded test and 
d ...