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

一、结构

#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结构体内存示意图

  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

  • 38
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值