之前若是有人拿个结构体或者联合体问我这个结构占用了多少字节的内存,我一定觉得这个人有点low, 直到某某公司的一个实习招聘模拟题的出现,让我不得不重新审视这个问题,

该问题大致如下:

typedef struct _A{
char a;
int b;
float c;
double d;
int *pa;
char* pc;
short e;
}A;
#pragma pack(pop)
int main(int argc, char *argv[])
{
printf("size = %d\n",sizeof(A));
return 0;
}

程序输出结果是()。
A size= 48
B size= 44
C size= 40
D size= 36

乍一看,这还不简单吗, 1+4+4+8+4+4+2=27个字节,这个最少的答案也是36啊!

有同学提示说数据对齐,这才注意到预编译指令#pragma pack(pop), 一百度,得到这样的答案:

作用:指定结构体、联合以及类成员的packing alignment;

语法:#pragma pack( [show] | [push | pop] [, identifier], n )

说明:

1,pack提供数据声明级别的控制,对定义不起作用;

2,调用pack时不指定参数,n将被设成默认值;

3,一 旦改变数据类型的alignment,直接效果就是占用memory的减少,但是performance会下降;

语法具体分析:

1,show:可选参数;显示当前packing aligment的字节数,以warning message的形式被显示;

2,push:可选参数;将当前指定的packing alignment数值进行压栈操作,这里的栈是the internal compiler stack,同时设置当前的packing alignment为n;如果n没有指定,则将当前的packing alignment数值压栈;

3,pop:可选参数;从internal compiler stack中删除最顶端的record;如果没有指定n,则当前栈顶record即为新的packing alignment数值;如果指定了n,则n将成为新的packing aligment数值;如果指定了identifier,则internal compiler stack中的record都将被pop直到identifier被找到,然后pop出identitier,同时设置packing alignment数值为当前栈顶的record;如果指定的identifier并不存在于internal compiler stack,则pop操作被忽略;

4,identifier:可选参数;当同push一起使用时,赋予当前被压入栈中的record一个名称;当同pop一起使用时,从internal compiler stack中pop出所有的record直到identifier被pop出,如果identifier没有被找到,则忽略pop操作;5,n:可选参数;指定packing的数值,以字节为单位;缺省数值是8,合法的数值分别是1、2、4、8、16。

因为没有push操作,internal compiler stack为空,所以这个条预编译指定在这里其实是没有任何作用的,使用下面这条指令查看当前的packing alignment = 8, 为默认的对齐参数。

#pragma pack(show)

再来看一下数据对齐的规则,复杂数据对齐主要分为数据成员的对齐和复杂数据整体对齐,两者都可以总结为

“在自身对齐参数和指定对齐参数中,选择小的对齐”

数据成员自身对齐参数为类型占用字节的长度,而复杂数据的自身对齐参数为最大的数据成员自身对齐参数,所谓对齐N,就是使得偏移量offset满足 offset%N = 0,并且使得数据长度尽可能短,第一数据成员的偏移量为0,

因此我们可以分析

成员变量的对齐

a的偏移量为 0,占用一个字节

此时的偏移量为0+1 =1,b的自身对齐参数即其长度为4,packing alignment =8, 顾应对齐4,顾其偏移量为4,(1+3)%4=0

此时偏移量为4+4= 8 ,而c也应对齐4, 8%4 = 0 ,故其偏移量为8

此时偏移量为8+4 = 12,而d的自身长度为8, 指定对齐参数也为8,故其对齐参数为8,所以其偏移量应为12+4=16,因为16%8 = 0

此时偏移量为16+8 = 24,而pa的对齐参数为4,24%4= 0,故其偏移量为24

此时偏移量为24+4 = 28,同理pc的偏移量也为28

此时偏移量为28+4 = 32,e的对齐参数为2,32%2 =0,故其偏移量为32,长度为2,数据成员对齐后结构体A的大小为

32+2 = 34个字节

整体对齐

结构体A中,最大的成员变量的长度为8,指定的packing alignment也是8,故其应对齐8,而数据成员对齐后其大小为34, 整体对齐后其大小应为40, 因为40%8 = 0。

结构体的数据对齐 #pragma浅谈的更多相关文章

  1. C结构体中数据的内存对齐问题

    转自:http://www.cnblogs.com/qwcbeyond/archive/2012/05/08/2490897.html 32位机一般默认4字节对齐(32位机机器字长4字节),64位机一 ...

  2. C语言结构体的字节对齐原则

    为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据 ...

  3. C语言结构体的内存对齐问题

    在C语言开发当中会遇到这样的情况: #include <stdio.h> struct test { int a; char b; }; int main(int argc, const ...

  4. C语言 结构体的内存对齐问题与位域

    http://blog.csdn.net/xing_hao/article/details/6678048 一.内存对齐 许多计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地 ...

  5. [转]C++结构体|类 内存对齐详解

    内存地址对齐,是一种在计算机内存中排列数据(表现为变量的地址).访问数据(表现为CPU读取数据)的一种方式,包含了两种相互独立又相互关联的部分:基本数据对齐和结构体数据对齐 . 为什么需要内存对齐?对 ...

  6. 关于结构体占用空间大小总结(#pragma pack的使用)

    关于C/C++中结构体变量占用内存大小的问题,之前一直以为把这个问题搞清楚了,今天看到一道题,发现之前的想法完全是错误的.这道题是这样的: 在32位机器上,下面的代码中 class A { publi ...

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

    结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但 ...

  8. 【C/C++】【VS开发】结构体存储空间数据对齐说明

    关于内存对齐 一: 1.什么是内存对齐 假设我们同时声明两个变量: char a; short b; 用&(取地址符号)观察变量a, b的地址的话,我们会发现(以16位CPU为例): 如果a的 ...

  9. 使用qsort对结构体的数据排序

    1007 DNA 排序 题目大意: 序列“未排序程度”的一个计算方式是元素乱序的元素对个数.例如:在单词序列“DAABEC'”中,因为D大于右边四个单词,E大于C,所以计算结果为5.这种计算方法称为序 ...

随机推荐

  1. angular7 Rxjs 异步请求

    Promise 和 RxJS 处理异步对比 Promise 处理异步: let promise = new Promise(resolve => { setTimeout(() => { ...

  2. Win32汇编学习(6):键盘输入消息

    这次,我们将要学习WINDOWS程序是如何处理键盘消息的. 理论: 因为大多数的PC只有一个键盘,所以所有运行中的WINDOWS程序必须共用它.WINDOWS 将负责把击键消息送到具有输入焦点的那个应 ...

  3. Hadoop数据类型

    hadoop包装了java的基本数据类型使他们实现以上的接口而且给予实现细节,这些类都实现了WritableComparable接口,能够在不同的hadoop节点之间毫无障碍的传输了.

  4. spring-data-jpa——如果使用了one-to-many,many-to-one的注解,在Jackson进行json字符串化时出现错误的解决方案

    参考资料: http://blog.csdn.net/remote_roamer/article/details/51330843 http://blog.csdn.net/xiaodaiye/art ...

  5. DAY15 模块

    一.模块 1.1 模块的定义:模块就是一系列功能的集合体 1.2 模块的四种存在方式: 1.使用python编写的.py文件(任一py文件都可以作为模块) 2.包:一堆py文件的集合体 3.使用C编写 ...

  6. spring cloud 版本号与 boot版本之间的对应关系(版本不对,会导致pom无法引入)

    版本号规则 Spring Cloud并没有熟悉的数字版本号,而是对应一个开发代号. 开发代号看似没有什么规律,但实际上首字母是有顺序的,比如:Dalston版本,我们可以简称 D 版本,对应的 Edg ...

  7. vnpy官网说明文档网址

    接触VNPY一年多,一直对作者设计原理和思想有所困惑.发一篇vnpy官网的说明文档,便于以后理解项目代码. http://www.vnpy.org/archives.html

  8. 『PyTorch x TensorFlow』第六弹_从最小二乘法看自动求导

    TensoFlow自动求导机制 『TensorFlow』第二弹_线性拟合&神经网络拟合_恰是故人归 下面做了三个简单尝试, 利用包含gradients.assign等tf函数直接构建图进行自动 ...

  9. Regex-Golf

    A man, a plan: 判断回文,如果不确定串长度情况下可以考虑利用反向引用构造pattern,例如: (.)\1  , (.)(.)\2\1 , (.)(.)(.)\3\2\1 ...但这里只 ...

  10. this理解

    <script type="text/javascript"> //"this关键字引用的是 包含它的那个函数 作为某个对象的方法 被调用时所属的那个对象&q ...