结构体的数据对齐 #pragma浅谈
之前若是有人拿个结构体或者联合体问我这个结构占用了多少字节的内存,我一定觉得这个人有点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浅谈的更多相关文章
- C结构体中数据的内存对齐问题
转自:http://www.cnblogs.com/qwcbeyond/archive/2012/05/08/2490897.html 32位机一般默认4字节对齐(32位机机器字长4字节),64位机一 ...
- C语言结构体的字节对齐原则
为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据 ...
- C语言结构体的内存对齐问题
在C语言开发当中会遇到这样的情况: #include <stdio.h> struct test { int a; char b; }; int main(int argc, const ...
- C语言 结构体的内存对齐问题与位域
http://blog.csdn.net/xing_hao/article/details/6678048 一.内存对齐 许多计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地 ...
- [转]C++结构体|类 内存对齐详解
内存地址对齐,是一种在计算机内存中排列数据(表现为变量的地址).访问数据(表现为CPU读取数据)的一种方式,包含了两种相互独立又相互关联的部分:基本数据对齐和结构体数据对齐 . 为什么需要内存对齐?对 ...
- 关于结构体占用空间大小总结(#pragma pack的使用)
关于C/C++中结构体变量占用内存大小的问题,之前一直以为把这个问题搞清楚了,今天看到一道题,发现之前的想法完全是错误的.这道题是这样的: 在32位机器上,下面的代码中 class A { publi ...
- C语言结构体变量字节对齐问题总结
结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但 ...
- 【C/C++】【VS开发】结构体存储空间数据对齐说明
关于内存对齐 一: 1.什么是内存对齐 假设我们同时声明两个变量: char a; short b; 用&(取地址符号)观察变量a, b的地址的话,我们会发现(以16位CPU为例): 如果a的 ...
- 使用qsort对结构体的数据排序
1007 DNA 排序 题目大意: 序列“未排序程度”的一个计算方式是元素乱序的元素对个数.例如:在单词序列“DAABEC'”中,因为D大于右边四个单词,E大于C,所以计算结果为5.这种计算方法称为序 ...
随机推荐
- [C++ Primer Plus] 第5章、循环和关系表达式(一)程序清单——指针自加减优先级
程序5.4 #include<iostream> using namespace std; ; void main() { long long factorials[Size]; fact ...
- CSS布局学习(三) - position属性定义及解释(官网直译)
static ①元素的位置是在文档正常布局流中的位置. ②设置top right bottom left与z-index无效. ③在未指定position时,static是默认值 以下例子进行说明: ...
- mysql常用的查询优化
原文链接:https://www.jb51.net/article/39221.htm 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2 ...
- Spring中ClassPathXmlApplication与FileSystemXmlApplicationContext的区别
Spring中ClassPathXmlApplication与FileSystemXmlApplicationContext的区别 一.概述 在项目中遇到加载不到Spring配置文件,简单分析后,写此 ...
- 更改ssh,ftp默认端口
1. 更改ssh端口 放置升级openssh之后做此步骤 配置文件/etc/ssh/sshd_config 注释掉Subsystem sftp /usr/libexec/openss ...
- java读取UTF-8的txt文件发现开头的一个字符问题
今天遇到一个奇葩问题,在读取一个TXT文件时,出现开头多了一个问号(?).如下图: 莫名奇妙的多了一个.最后通过网上资料,知道在Java中,class文件采用utf8的编码方式,JVM运行时采用utf ...
- Redis中Pipeline的使用
通过Java访问Redis,我们一般使用Jedis,示例代码如下: Jedis jedis = new Jedis("172.23.88.107", 6379); jedis.se ...
- [Windows端口占用] 找到占用端口的进程并杀死
命令行: netstat -aon|findstr "80" 会得到类似下列的数据 TCP 0.0.0.0:80 0.0.0.0:0 LISTENING 2736 2736代表占用 ...
- 『Python』socket网络编程
Python3网络编程 '''无论是str2bytes或者是bytes2str其编码方式都是utf-8 str( ,encoding='utf-8') bytes( ,encoding='utf-8' ...
- 『Python CoolBook』C扩展库_其六_从C语言中调用Python代码
点击进入项目 一.C语言运行pyfun的PyObject对象 思路是在C语言中提供实参,传给python函数: 获取py函数对象(PyObject),函数参数(C类型) 获取GIL(PyGILStat ...