#pragma pack(push) 和#pragma pack(pop) 以及#pragma pack()
我们知道结构体内存对齐字节可以通过#pragma pack(n) 的方式来指定。
但是,有没有想过一个问题,某些时候我想4字节对齐,有些时候我又想1字节或者8字节对齐,那么怎么解决这个问题呢?
此时,#pragma pack(push) 和#pragma pack(pop) 以及#pragma pack()应运而生。
看测试代码:(说明,64位GCC,默认8字节对齐)
屏蔽了的代码先别看,只看这个结构体,在默认8字节对齐的方式下,sizeof大小为24个字节,这不再做分析,之前随笔分析过了。
然后我加上编译器按照4字节对齐的代码之后:
那么现在,我再新建一个结构体B,内容和结构体C一样,只是对齐方式向分别采取不同的方式:
#include <stdio.h> #pragma pack(4)
struct C {
double d;
char b;
int a;
short c;
};
#pragma pack()
struct B {
double d;
char b;
int a;
short c;
};
像上面那样处理之后,输出:先打印结构C,再打印结构B
这说明了,在强制4字节对齐之后,我加上#pragma pack() ,能够让程序恢复默认对齐(这里是8字节)状态。
#pragma pack() 能够取消自定义的对齐方式,恢复默认对齐。
继续测试:
#pragma pack(4)
struct CC {
double d;
char b;
int a;
short c;
};
#pragma pack(pop)
struct BB{
double d;
char b;
int a;
short c;
};
输出:
好像没什么作用的感觉,那么再加上一个#pragma pack(push)试试呢?
#include <stdio.h> #pragma pack(push)
#pragma pack(4)
struct CC {
double d;
char b;
int a;
short c;
};
#pragma pack(pop)
struct BB{
double d;
char b;
int a;
short c;
};
int main(void)
{ printf("%u\n%u\n",sizeof(struct CC),sizeof(struct BB));
return ;
}
这样似乎改变了,有不同的地方体现了出来。
#pragma pack(push):
英文单词push是“压入”的意思。编译器编译到此处时将保存对齐状态(保存的是push指令之前的对齐状态)。
#pragma pack(pop):
英文单词pop是”弹出“的意思。编译器编译到此处时将恢复push指令前保存的对齐状态(请在使用该预处理命令之前使用#pragma pack(push))。
push和pop是一对应该同时出现的名词,只有pop没有push不起作用,只有push没有pop可以保持之前对齐状态(但是这样就没有使用push的必要了)。
这样就可以知道,当我们想要一个结构体按照4字节对齐时,可以使用#pragma pack(4) ,最后又想使用默认对齐方式时,可以使用#pragma pack() ;
也可以使用:
#pragma pack(push)
#pragma pack(4)
struct。。。
#pragma pack(pop)
这样在push和pop之间的结构体就可以按照pack指定的字节(这里是4字节对齐方式),而pop之后的结构体按照#pragma pack(push) 前对齐方式。
eg:
#include <stdio.h>
#pragma pack(2)
#pragma pack(push)
#pragma pack(4)
struct CC {
double d;
char b;
int a;
short c;
}; #pragma pack(1)
struct BB{
double d;
char b;
int a;
short c;
};
#pragma pack(pop)
struct AA{
double d;
char b;
int a;
short c;
};
int main(void)
{ printf("%u\n%u\n%u\n",sizeof(struct CC),sizeof(struct BB),sizeof(struct AA));
return ;
}
先按照2字节对齐,然后push保存2字节对齐,然后又强制4字节对齐,打印CC为20字节,然后强制1字节对齐,打印BB为15字节,然后pop,pop会让编译器回到push之前的对齐方式(这里是2字节对齐),打印AA(按照2字节对齐)16字节。
注意,#pragma pack() 取消自定义对齐方式,恢复默认方式,而push之后pop是回到push指令之前的对齐方式。
eg:
#include <stdio.h>
#pragma pack(2)
#pragma pack(push)
#pragma pack(4)
struct CC {
double d;
char b;
int a;
short c;
}; #pragma pack(1)
struct BB{
double d;
char b;
int a;
short c;
};
#pragma pack()
struct AA{
double d;
char b;
int a;
short c;
};
int main(void)
{ printf("%u\n%u\n%u\n",sizeof(struct CC),sizeof(struct BB),sizeof(struct AA));
return ;
}
只把pop改成pack()打印如下:
最后回到的不是2字节对齐,而是默认的8字节对齐。
还有延伸点:
上图红色处等价于下面屏蔽的两句。
语法:
#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的数值,以字节为单位;
另外:
__attribute(aligned(n)),让所作用的数据成员对齐在n字节的自然边界上;如果结构中有成员的长度大于n,则按照最大成员的长度来对齐;
__attribute((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐
#pragma pack(push) 和#pragma pack(pop) 以及#pragma pack()的更多相关文章
- #pragma pack(push,1)与#pragma pack(pop)
这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n) 作用:C编译器将按照n个字节对 ...
- 请教网友:#pragma pack(push) #pragma pack(pop)无效
//try 一 try #pragma back(push) #pragma pack(2) struct E { char a; short b; double c; float d; char e ...
- 详解C/C++中的的:#pragma pack(push) 、#pragma pack(pop) 和#pragma pack()
前言 我们知道结构体内存对齐字节可以通过#pragma pack(n) 的方式来指定. 但是,有没有想过一个问题,某些时候我想4字节对齐,有些时候我又想1字节或者8字节对齐,那么怎么解决这个问题呢? ...
- #pragma pack(push,1)与#pragma pack(1)的区别
这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n) 作用:C编译器将按照n个字节对 ...
- warning malformed '#pragma pack(push[, id], n)' - ignored
bmp.c:8: warning: malformed '#pragma pack(push[, id], <n>)' - ignored bmp.c:33: warning: #prag ...
- (转载)关于#pragma pack(push,1)和#pragma pack(1)
转载http://www.rosoo.net/a/201203/15889.html 一.#pragma pack(push,1)与#pragma pack(1)的区别 这是给编译器用的参数设置,有关 ...
- 【转】#pragma pack(push,1)与#pragma pack(1)的区别
这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n) 作用:C编译器将按照n个字节对 ...
- #pragma pack(push,1)与#pragma pack(1)的区别(转)
这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n) 作用:C编译器将按照n个字节对 ...
- 【VS开发】#pragma pack(push,1)与#pragma pack(1)的区别
这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n) 作用:C编译器将按照n个字节对 ...
随机推荐
- Gedit 有用插件介绍
刚刚接触Ubuntu,对于高手们用的Vim,本人只能望尘莫及.但是,Ubuntu自带的Gedit让我找到了windows的感觉,而且在添加一些插件后更加喜欢这个工具了. gedit本身带有一些常用插件 ...
- 富文本编辑器 CKeditor 配置使用
作者:Tyler Ning出处:http://www.cnblogs.com/tylerdonet/本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连 ...
- 【Smali】Smali文件的动态调试
1.简介 smalidea是一个IntelliJ IDEA/Android Studio smali语言插件,可实现动态调试smali代码.下载地址为:https://github.com/Jesus ...
- Docker : endpoint with name xxx already exists.
停止不了容器,在尝试过: docker stop [container_id] docker kill [container_id] 都不行之后,强制删除容器: docker rm -f [cont ...
- iconv 中文截断问题的解决方法
GB2312 转换为 UTF-8 <?php $content = iconv('GB2312', 'UTF-8', $content); // $content为字符串 ?> iconv ...
- mysql-binlog_cache_size
二进制日志缓冲区吗,默认是32k.该参数是基于会话的,不要设置过大. 当事务的记录大于设定的binlog_cache_size时,mysql会把缓冲区中的日志信息写入一个临时文件中,所以该值也不能设置 ...
- iOS 优秀开源框架 开源包 开发包 from : Podfile of chatsecure ---待完善
前段时间发现chatsecure的podfile中使用了很多非常优秀的开源包 和 大公司的sdk. 拿出来分享下. 各个类库的作用待完善. platform :ios, "7.0" ...
- C++中的成员对象
原文链接: http://blog.csdn.net/rhzwan123/article/details/2105205 [概念] 成员对象:当一个类的成员是另一个类的对象时,这个对象就叫成员对象.概 ...
- 跟我学SharePoint2013视频培训课程——设置列表名称、描述、导航等基本信息(12)
课程简介 第12天,怎样在SharePoint 2013设置列表名称.描述.导航等基本信息. 视频 SharePoint 2013 交流群 41032413
- C#右下角弹出消息框
打开QQ的时候,QQ新闻弹出窗体在屏幕的右下角就会慢慢升起一个小窗口,占用的地方不大,可以起到提示的作用.下面就让我们来看看,怎样用系统API来轻松实现这个功能.API原型函数:bool Animat ...