转载: #pragma pack(push,1) & #pragma pack(pop)

1 引子

在程序中,有的时候我们定义结构体的时候,要用#pragma pack(push,1) & #pragma pack(pop)类似代码将结构体包起来。

一般形式如下:

#pragma pack(push,1);

struct A

{

} ;

#pragma pack(pop);

这么做有什么目的呢?

注:下列内容来自网络。

2 #pragma pack简介

#pragma pack是指定数据在内存中的对齐方式,

在 C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如数组、结 构、联合等)的数据单元。在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序 存储,第一个成员的地址和整个结构的地址相同。

例 1:

struct sample
{
char a;
double b;
};


不用#pragma pack(1)和#pragma
pack()括起来,则sample按编译器默认方式对齐(成员中size最大的那个)。即按8字节(double)对齐,则
sizeof(sample)==16.成员char a占了8个字节(其中7个是空字节)

若用#pragma pack(1),则sample按1字节方式对齐sizeof(sample)==9.(无空字节)

例 2:下面的结构各成员空间分配情况:
struct test
{
     char x1;
     short x2;
     float x3;
     char x4;
};

结构的第一个成员x1,其偏移地址为0,占据了第1个字节。第二个成员x2为short类型,其起始地址必须2字节对界,因此,编译器在x2和x1之间填
充了一个空字节。结构的第三个成员x3和第四个成员x4恰好落在其自然对界地址上,在它们前面不需要额外的填充字节。在test结构中,成员x3要求4字
节对界,是该结构所有成员中要求的最大对界单元,因而test结构的自然对界条件为4字节,编译器在成员x4后面填充了3个空字节。整个结构所占据空间为
12字节。更改C编译器的缺省字节对齐方式
     在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:
  · 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
     · 使用伪指令#pragma pack (),取消自定义字节对齐方式。

另外,还有如下的一种方式:
     · __attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。
     · __attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。

以上的n = 1, 2, 4, 8, 16... 第一种方式较为常见。

3 应用实例

 
 在网络协议编程中,经常会处理不同协议的数据报文。一种方法是通过指针偏移的方法来得到各种信息,但这样做不仅编程复杂,而且一旦协议有变化,程序修改
起来也比较麻烦。在了解了编译器对结构空间的分配原则之后,我们完全可以利用这一特性定义自己的协议结构,通过访问结构的成员来获取各种信息。这样做,不
仅简化了编程,而且即使协议发生变化,我们也只需修改协议结构的定义即可,其它程序无需修改,省时省力。下面以TCP协议首部为例,说明如何定义协议结
构。其协议结构定义如下:

#pragma pack(1) // 按照1字节方式进行对齐

struct TCPHEADER
{
     short SrcPort; // 16位源端口号

short DstPort; // 16位目的端口号

int SerialNo; // 32位序列号

int AckNo; // 32位确认号

unsigned char HaderLen : 4; // 4位首部长度

unsigned char Reserved1 : 4; // 保留6位中的4位

unsigned char Reserved2 : 2; // 保留6位中的2位

unsigned char URG : 1;
     unsigned char ACK : 1;
     unsigned char PSH : 1;
     unsigned char RST : 1;
     unsigned char SYN : 1;
     unsigned char FIN : 1;
     short WindowSize; // 16位窗口大小

short TcpChkSum; // 16位TCP检验和

short UrgentPointer; // 16位紧急指针

};
#pragma pack()

转自:http://blog.csdn.net/mannhello/article/details/5384431

时间: 2024-10-12 22:09:12

转载: #pragma pack(push,1) & #pragma pack(pop)的相关文章

释析#pragma pack(push,n) #pragma pack(n) #pragma pack() #pragma pack(pop)

今天阅读别人写得的代码时,发现了#pragma pack(n) 这段代码,不知道加这个代码是什么个意思,然后自己就查了一下资料,然后写了段代码试了试,还有点那么个意思, 含义是:告诉编译器设置结构体的边界字节对齐方式,也就是所有数据在内存中是存储的方式. 这句话挺模糊的, 我们接下来先看几个例子程序, 例子一 struct weikangc { int nAge; char cSex; }; int main(int argc, char* argv[]) { printf("%d\r\n&qu

#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个字节,这不再做分析,之前随笔分析过了. 然

#pragma pack(push,1)与#pragma pack(pop)

这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n)             作用:C编译器将按照n个字节对齐.#pragma pack ()               作用:取消自定义字节对齐方式. #pragma  pack (push,1)     作用:是指把原来对齐方式设置压栈,并设新的对齐方式设置为一个字节对齐 #pragma pack(pop)            作用:恢复对齐状态 因

#pragma pack(push,1)与#pragma pack(1)的区别(转)

这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n)             作用:C编译器将按照n个字节对齐.#pragma pack ()               作用:取消自定义字节对齐方式. #pragma  pack (push,1)     作用:是指把原来对齐方式设置压栈,并设新的对齐方式设置为一个字节对齐 #pragma pack(pop)            作用:恢复对齐状态 因

#pragma pack(push,1)与#pragma pack(1)的区别

这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式. #pragma pack (n)             作用:C编译器将按照n个字节对齐. #pragma pack ()               作用:取消自定义字节对齐方式. #pragma  pack (push,1)     作用:是指把原来对齐方式设置压栈,并设新的对齐方式设置为一个字节对齐 #pragma pack(pop)            作用:恢复对齐状态

warning malformed '#pragma pack(push[, id], n)' - ignored

bmp.c:8: warning: malformed '#pragma pack(push[, id], <n>)' - ignored bmp.c:33: warning: #pragma pack (pop) encountered without matching #pragma pack (push, <n>) 这个警告很重要不能忽略,我遇到的这个问题适用于编译器比较老的,因为韦东山自带的虚拟机Ubuntu9.10用的是/work/tools/gcc- 3.4.5 -gl

pragma comment的使用 pragma预处理指令详解

pragma comment的使用 pragma预处理指令详解 #pragma comment( comment-type [,"commentstring"] ) 该宏放置一个注释到对象文件或者可执行文件.comment-type是一个预定义的标识符,指定注释的类型,应该是compiler,exestr,lib,linker之一.commentstring是一个提供为comment-type提供附加信息的字符串,Remarks:1.compiler:放置编译器的版本或者名字到一个对象

【转载】Git push时重复输入用户名密码的问题

在windows上使用git来push到github服务器的时候,每次都需要填写用户名/邮箱.密码,很麻烦.最近用hexo写博客,需要频繁地进行博客配置和预览,而每次预览执行hexo deploy都需要输入用户名.密码验证,不胜其烦,今天下决心解决. 尽管github提供了SSH方式进行本地和服务端的链接,可是按照网站说明设置好之后,这个问题仍然得不到解决.尝试了好几次,最终用下面这个方法解决了. 首先添加环境变量. 在用户文件夹如C:\Users\zhangsan下新建一个名为_netrc的文

push()、shift()与pop()、unshift()、splice()

1.末端的添加和移除:push()是用来在数组末端添加项,pop()在数组末端移除项: 2.前端的添加和移除:shift()在移除数组的第一个项(前端),unshift()在数组前端添加项: 3.push(),unshift()在推入多个项时,各个项之间的顺序不变 4.push(),unshift()将数组的长度+1并返回的是数组的长度,pop(),shift()将数组length-1并返回的是移除的项 例如: var num=new Array(); num.push("1",&qu