参考

百度百科内存对齐

对齐作用

可以使得以最少的次数将操作数加载到寄存器中,如果数据没有对齐,则当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. 在cad2008引用了错误的com接口的dll导致出现了

    请求“System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.0.0, Culture=neutral, Publi ...

  2. Java知识锦囊

    最近突然想回顾一下之前的文章,回顾复习一下,正好把觉得还不错的文章收录到这里,方便查阅 Java 2018-04-02 Java计数器之CountDownLatch.CyclicBarrier.Sem ...

  3. jq 复习帖子 常用操作

     1绝对定位(abs)与相对定位(relative)    区别是相对定位参照自己的位置进行移动(当然需要设置top left这些生效)并且原来的位置保留着 偏移后会把其它的层遮罩住    绝对定位就 ...

  4. Vue的声明周期

    以下简单介绍,以自己的理解进行分析.如有不好,请大牛勿喷!!!!!! new Vue() 创建 Vue 实例 beforeCreate(){}: 第一生命周期 表示实例完全创建出来,此函数执行是,da ...

  5. Vue2.5开发去哪儿网App 第二章笔记

    Vue完成  TodoList 1.默认方式 <!DOCTYPE html> <html lang="en"> <head> <meta ...

  6. 轮播图采用js、jquery实现无缝滚动和非无缝滚动的四种案例实现,兼容ie低版本浏览器

    项目源代码下载地址:轮播图 以下为项目实现效果:(由于gif太大,所以只上传一张图片,但效果完全能实现,经测试,在ie各版本浏览器及chrome,firefox等浏览器中均能实现效果,可以实现点击切换 ...

  7. Python 模块 和 包

    模块 os模块 路径拼接 os.path.join

  8. Java之ServiceLoader

    转载请注明源出处:http://www.cnblogs.com/lighten/p/6946683.html 1.简介 JDK1.6之后,java.util包下多了一个类ServiceLoader,其 ...

  9. jenkins 通过shell启动tomcat会随着job完成而被自动关闭的解决方法

    jenkins 通过shell启动tomcat会随着job完成而被自动关闭的解决方法 填入BUILD_ID=随便填什么 原理是:我不知道

  10. Mac 下使用 brew 安装软件

    官网:http://brew.sh/安装 ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/m ...