C #pragma pack(push,1) #pragma pack(pop)解析

发布时间 2024-01-03 10:22:10作者: mkmkbj

https://blog.csdn.net/qq_22398523/article/details/81671121

一、结构

  1. #ifdef _WIN32
  2. #pragma pack( push, 1 )
  3. #else
  4. #pragma pack(1)
  5. #endif
  6. Typedef  struct
  7. {
  8. }
  9. #ifdef _WIN32
  10. #pargma pack(pop)
  11. #else
  12. #pragma pack()
  13. #endif

 

二、对 #pragma pack()的理解

在程序中,我们有时候在定义结构体时,需要使用 #pargma pack(push,1) 和 #pragma pack(pop) 类似代码将结构体包裹起来,形式如上。

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

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

如果不用#pargma pack()包裹,则结构体按编译器默认对其方式(成员中size最大的那个)对齐。这里包括以下三个原则:

原则1:数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。

原则2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。)

原则3:收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。

三、示例

// 文件 testpragram.c

  1. #include <stdio.h>
  2. struct test
  3. {
  4. char x1;
  5. float x3;
  6. short x2;
  7. char x4;
  8. };
  9. struct test2
  10. {
  11. char x1;
  12. double x2;
  13. short x3;
  14. char x4;
  15. short x5;
  16. struct test t;
  17. };
  18. int main(void)
  19. {
  20. struct test t;
  21. struct test2 t2;
  22. int len;
  23. int len2;
  24. len = sizeof(t);
  25. len2 = sizeof(t2);
  26. setvbuf(stdout,NULL,_IONBF,0);
  27. printf( "len: %d, len2: %d .", len, len2 );
  28. return 0;
  29. }

test结构体内存如下图,蓝色实线框代表实际占用字符,红色虚线框代表空白字符

图1 test结构体内存示意图

  1. char x1 占一个字节,位置如图中1。
  2. Float x3 占四个字节,因此需要从4的整数倍开始,故char x1后面补三位,x3存在5-8字节处。
  3. Short x2 占两个字节,8是2的整数倍,因此x2放在9-10字节处。
  4. Char x4 占一个字节,因此放在11处。
  5. 整个结构体中,最长的是float ,占四个字节,因此使用sizeof()函数时,长度是4的整数倍,故char x4后面补一位,即图中12位置处。

Sizeof(test) 的返回值为12。

Test2结构体内存示意图如下:

图2 test2结构体内存占用示意图

  1. char x1 占一个字节,位置如图2中1
  2. Double x2 占8个字节,从8的整数倍开始,因此,x1后面补七个字节2-8,x2放在9-16字节处
  3. Short x3 占两个字节,从2的整数倍开始,因此放在17-18字节处
  4. Char x4 占一个字节,存放在19字节处
  5. Short x5 占两个字节,从2的整数倍开始,因此x4后面补一个字节20,x5存放在21-22字节处
  6. Test t 结构体,其数据元素最大占4个字节(float),从4的整数倍开始,因此x5后面补两个字节23-24
  7. 然后依次按规则存放test 结构体中的数据

Sizeof(test2)返回值为40

使用#pragma pack(push,1) #pragma pack(pop) 或 #pragma pack(1) #pragma pack(),使结构体按照自己的实际大小顺序存储。

除了1,还可以指定为2,4,8,16 。

四、补充 #pragma warning

示例: #pragma warning(disable:4786)

说明:该指令允许有选择性的修改编辑器的警告行为。

        指令格式如下:

#pragma warning( warning-specifier : warning-number-list [; warning-specifier : warning-number-list...]
#pragma warning( push[ ,n ] )
#pragma warning( pop )

主要用到的警告表示有如下几个:

once:只显示一次(警告/错误等)消息
default:重置编译器的警告行为到默认状态
1,2,3,4:四个警告级别
disable:禁止指定的警告信息
error:将指定的警告信息作为错误报告

举例说明:

#pragma warning( disable : 4507 34; once : 4385; error : 164 )  
等价于:  
#pragma warning(disable:4507 34)  // 不显示4507和34号警告信息  
#pragma warning(once:4385)        // 4385号警告信息仅报告一次  
#pragma warning(error:164)        // 把164号警告信息作为一个错误。  
同时这个pragma warning 也支持如下格式:  
#pragma warning( push [ ,n ] )  
#pragma warning( pop )  
这里n代表一个警告等级(1---4)。  
#pragma warning( push )保存所有警告信息的现有的警告状态。  
#pragma warning( push, n)保存所有警告信息的现有的警告状态,并且把全局警告  
等级设定为n。   
#pragma warning( pop )向栈中弹出最后一个警告信息,在入栈和出栈之间所作的  
一切改动取消。例如:  
#pragma warning( push )  
#pragma warning( disable : 4705 )  
#pragma warning( disable : 4706 )  
#pragma warning( disable : 4707 )  
#pragma warning( pop )

在这段代码的最后,重新保存所有的警告信息(包括4705,4706和4707)

在使用标准C++进行编程的时候经常会得到很多的警告信息,而这些警告信息都是不必要的提示,
所以我们可以使用#pragma warning(disable:4786)来禁止该类型的警告

在vc中使用ADO的时候也会得到不必要的警告信息,这个时候我们可以通过
#pragma warning(disable:4146)来消除该类型的警告信息

补充部分来源:

https://blog.csdn.net/weixin_38271274/article/details/82893337