参考

百度百科内存对齐

对齐作用

可以使得以最少的次数将操作数加载到寄存器中,如果数据没有对齐,则当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. USACO December 铂金Maxflow

    USACO 2015 December Contest, Platinum Problem 1. Max Flow Farmer John has installed a new system of ...

  2. odoo开发笔记--自定义server action页面跳转注意

    场景描述: 在添加自定义服务器动作 “复制全部”后发现直接创建了新的记录,并且直接进入到form保存完的状态. 如何解决: if yourself_obj_copy: return { 'type': ...

  3. Proxy代理模式(结构型模式)

    1.问题 在面向对象系统中,有些对象由于某种原因(比如创建对象的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等),直接访问会给调用者带来麻烦,那么如何在不损失接口透明性的情况下,解决这些麻 ...

  4. 转:TCP为什么要3次握手和4次挥手时等待2MSL、 TCP如何保证消息顺序以及可靠性到达

    关于tcp三次握手.四次挥手可以看这里:TCP与UDP的差别以及TCP三次握手.四次挥手 1.TCP为甚要3次握手? 在谢希仁著<计算机网络>第四版中讲“三次握手”的目的是“为了防止已失效 ...

  5. 【从0到1学javascript】javascript数据结构----数组

    javascript中对数组的定义 数组是一种特殊的对象,用来表示偏移量的索引是该对象的属性,索引可以是整数.这些数字索引在内部被转换成字符串类型.这是因为javascript对象中的属性名必须是字符 ...

  6. WTF小程序之原生遇见mpvue

    事情是这样的,我们有一个原生(wxml,wxss,js,json)写的小程序,要加入一个新的模块,并且时间比较紧张.所以我们选择了采用mpvue开发一个分包(subpackage),加入到原生小程序中 ...

  7. Vue.js之组件(component)

    从结构上看,组件之于实例,就好比轮子之于汽车.从属性和方法来看,组件有实例的大部分方法,如果Vue实例是孙悟空,组件就好比实例的一个毫毛,变化多端却为Vue实例所用. 目录: 组件的注册 is的作用 ...

  8. 一道JS面试题引发的血案

    刚入职新公司,属于公司萌新一枚,一天下午对着屏幕看代码架构时. BI项目组长给我看了一道面试别人的JS面试题. 虽然答对了,但把理由说错了,照样不及格. 话不多说,直接上题: var a = 1; s ...

  9. Font Awesome 4.0.3 提供了369个网页常用的矢量字体图标,新浪、人人 的矢量图标也到其中哟

    要求 必备知识 本文要求基本了解html与css前端代码. 运行环境 普通浏览器,兼容IE7 源码下载 下载地址 Font Awesome 为您提供了一套可缩放的字体矢量图标,可以快速自定义图标的大小 ...

  10. vmrun 批量创建vmware虚拟机

    1 准备模板机 具体步骤如下: 1. 下载镜像安装系统 https://mirrors.aliyun.com/centos/7.5.1804/isos/x86_64/ 2. 安装完成配置好IP ,关闭 ...