C #pragma pack(push,1) #pragma pack(pop)解析
https://blog.csdn.net/qq_22398523/article/details/81671121
一、结构
- #ifdef _WIN32
- #pragma pack( push, 1 )
- #else
- #pragma pack(1)
- #endif
-
- Typedef struct
-
- {
-
- }
-
- #ifdef _WIN32
- #pargma pack(pop)
- #else
- #pragma pack()
- #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
- #include <stdio.h>
-
- struct test
- {
- char x1;
- float x3;
- short x2;
- char x4;
- };
-
- struct test2
- {
- char x1;
- double x2;
- short x3;
- char x4;
- short x5;
- struct test t;
- };
-
- int main(void)
- {
- struct test t;
- struct test2 t2;
- int len;
- int len2;
- len = sizeof(t);
- len2 = sizeof(t2);
- setvbuf(stdout,NULL,_IONBF,0);
-
- printf( "len: %d, len2: %d .", len, len2 );
- return 0;
- }
test结构体内存如下图,蓝色实线框代表实际占用字符,红色虚线框代表空白字符
图1 test结构体内存示意图
- char x1 占一个字节,位置如图中1。
- Float x3 占四个字节,因此需要从4的整数倍开始,故char x1后面补三位,x3存在5-8字节处。
- Short x2 占两个字节,8是2的整数倍,因此x2放在9-10字节处。
- Char x4 占一个字节,因此放在11处。
- 整个结构体中,最长的是float ,占四个字节,因此使用sizeof()函数时,长度是4的整数倍,故char x4后面补一位,即图中12位置处。
Sizeof(test) 的返回值为12。
Test2结构体内存示意图如下:
图2 test2结构体内存占用示意图
- char x1 占一个字节,位置如图2中1
- Double x2 占8个字节,从8的整数倍开始,因此,x1后面补七个字节2-8,x2放在9-16字节处
- Short x3 占两个字节,从2的整数倍开始,因此放在17-18字节处
- Char x4 占一个字节,存放在19字节处
- Short x5 占两个字节,从2的整数倍开始,因此x4后面补一个字节20,x5存放在21-22字节处
- Test t 结构体,其数据元素最大占4个字节(float),从4的整数倍开始,因此x5后面补两个字节23-24
- 然后依次按规则存放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