#pragma的一些用法

#pragma的一些用法

#include "stdafx.h"
#include <iostream>
using namespace std;

#if 0

在#Pragma是预处理指令它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。
#pragma指令对每个编译器给出了一个方法, 在保持与C和C ++语言完全兼容的情况下, 给出主
机或操作系统专有的特征。依据定义, 编译指示是机器 或操作系统专有的, 且对于每个编译器
都是不同的。 其格式一般为 : #Pragma Para 其中Para 为参数,下面来看一些常用的参数。

(1)message 参数。 Message 参数是我最喜欢的一个参数,它能够在编译信息输出窗 口中输出
相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为: #Pragma message(“消息文本”)
当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。 当我们在程序中定义了许多宏来控
制源代码版本的时候,我们自己有可能都会忘记有没有正 确的设置这些宏,此时我们可以用这条指令在
编译的时候就进行检查。假设我们希望判断自 己有没有在源代码的什么地方定义了_X86这个宏可以用下
面的方法
#ifdef _X86 #Pragma message(“_X86 macro activated!”) 
#endif 
当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示“_ X86 macro activated!”
我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了。

(2)另一个使用得比较多的pragma参数是code_seg。格式如: 
#pragma code_seg([\section - name\[, \section - class\]]) 
它能够设置程序中函数代码存放的代码段,使用没有section - name字符串的#pragmacode_seg可在
编译开始时将其复位,当我们开发驱动程序的时候就会使用到它。

(3)#pragma once(比较常用) 只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,
这条指令实际上在VC6 中就已经有了,但是考虑到兼容性并没有太多的使用它。

(4)#pragma hdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。BCB可以预编译头文件
以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一
些头文件。 有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。你可以用
#pragma startup
指定编译优先级,如果使用了#pragma package(smart_init) ,BCB就会根据优先级的大小先后编译。

(5)#pragma resource \*.dfm\表示把*.dfm文件中的资源加入工程。*.dfm中包括窗体 外观的定义。

(6)#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)。

(7)pragma comment(...) 该指令将一个注释记录放入一个对象文件或可执行文件中。 常用的lib关键字,
指定连接要使用的库 比如我们连接的时候用到了 WSock32.lib,你当然可以不辞辛苦地把它加入到你的工程中。
但是我觉得更方便的方法是使用 #pragma 指示符,指定要连接的库: #pragma comment(lib, "WSock32.lib")
可以帮我们连入一个库文件。

(8)通过#pragma pack(n)改变C编译器的字节对齐方式 在C语言中,结构是一种复合数据类型,
其构成元素既可以是基本数据类型(如int、 long、float等)的变量,也可以是一些复合数据类型(如数组、
结构、联合等)的 数据单元。在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分 配空间。
各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和 整个结构的地址相同。 
例如下面的结构各成员空间分配情况:
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...第一种方式较为常见。应用实例在网络协议编程中,经常会处理不同协议的数据报文。
一种方法是通过指针偏移的方法来得到各种信息,但这样做不仅编程复杂,而且一旦协议有变化,程序修改起来也比较
麻烦。在了解了编译器对结构空间的分配原则之后,我们完全可以利用这 一特性定义自己的协议结构,通过访问结构
的成员来获取各种信息。这样做,不仅简化了编程,而且即使协议发生变化,我们也只需修改协议结构的定义即可,
其它程序无需修改,省时省力。下面以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() // 取消1字节对齐方式

#endif

 

### 关于 `#pragma pack` 和 `#pragma anon_unions` 的用法详解 #### 1. `#pragma pack` 的作用 `#pragma pack` 是一种编译器指令,用于控制结构体成员之间的内存对齐方式。默认情况下,C/C++ 编译器会对结构体中的成员变量进行字节对齐优化,以提高访问速度。然而,在某些场景下(如嵌入式开发或网络通信),需要精确控制结构体的布局,此时可以使用 `#pragma pack`。 - **语法**: ```c #pragma pack(n) ``` 其中 `n` 表示指定的对齐单位,通常为 1、2、4 或 8 字节。设置后,结构体会按照该对齐方式进行排列。 - **具体功能**: - 当前文件范围内的所有后续定义都会受到此 pragma 影响。 - 如果希望仅影响特定部分代码,则可配合 `push` 和 `pop` 使用[^1]。 #### 2. `#pragma pack(push/pop)` 的作用 为了防止全局修改对齐方式的影响,可以通过 `push` 和 `pop` 来保存和恢复之前的对齐状态: - **语法**: ```c #pragma pack(push, n) // 将当前对齐方式压栈并设置新的对齐方式 ... #pragma pack(pop) // 恢复之前保存的对齐方式 ``` - **实际应用案例**: 下面是一个典型的例子,展示如何通过 `pack(push/pop)` 控制结构体内存布局: ```c #pragma pack(push, 1) // 设置对齐方式为 1 字节并对旧状态进行保存 typedef struct { char a; int b; short c; } PackedStruct; #pragma pack(pop) // 恢复原来的对齐方式 ``` 在这个例子中,`PackedStruct` 中的字段不会因为默认对齐而增加额外填充字节,从而节省空间。 #### 3. `#pragma anon_unions` 的作用 `#pragma anon_unions` 用于启用或禁用 C 结构体中的匿名联合体支持。匿名联合体允许直接访问联合体内部的成员,而不必显式指明联合体名称。 - **默认行为**: 默认情况下,许多编译器会关闭匿名联合体的支持,除非明确开启它。 - **语法**: ```c #pragma anon_unions // 启用匿名联合体支持 #pragma no_anon_unions // 禁用匿名联合体支持 (通常是默认值)[^2] ``` - **实际应用场景**: 假设有一个包含匿名联合体的结构体: ```c #pragma anon_unions // 开启匿名联合体支持 typedef struct { union { float fValue; int iValue; }; } AnonymousUnionExample; AnonymousUnionExample example; example.fValue = 3.14f; // 可以直接访问联合体成员 printf("%d\n", example.iValue); ``` 这种写法简化了代码逻辑,尤其适用于硬件寄存器映射等场合[^2]。 --- ### 总结 - `#pragma pack` 主要用来调整结构体成员间的内存对齐策略,减少不必要的填充字节。 - `#pragma pack(push/pop)` 提供了一种局部化的方式管理对齐选项,避免污染整个程序环境。 - `#pragma anon_unions` 则提供了更灵活的方式来处理匿名联合体,使得复杂的数据结构更加简洁易读。 以上工具在嵌入式系统编程以及跨平台兼容性设计中有广泛应用价值。 ```python def align_memory(size, alignment=4): """计算按指定边界对齐后的大小""" return ((size + alignment - 1) // alignment) * alignment ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值