代码改变世界

#pragma指令的用法

2012-03-28 19:10  Rollen Holt  阅读(748)  评论(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"] ] ) 
它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。 

(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关键字,可以帮我们连入一个库文件。

 

#pragma pack(1) 作用

主要用来设置结构定义的字节对齐方式,比如是单字节对齐,双字节对齐等,比如如果是双字节对齐,那么结构的成员变量的地址必须是2的整数倍,这就造成了字节补齐,但是提高了访问速度。单字节呢,就是没有补齐,成员变量的地址是连续的,其他依次类推,通常是4,8等。通常用于网络传输数据,特别是传输整个结构时,必须采取单字节对齐,这样才可以直接把结构地址,以及结构长度,作为Send的参数发送整个结构,否则只能依次发送结构的成员,要不然会出现结构解释的差异。 

另外,在Project->Setting->C/C++->Code Generation->Struct member alignment中可以设置结构的对齐方式。  

传输结构时和pack无关,只要Recv端定义的结构和Send方一样就没问题了。 
pack多用于Hook程序,比如Hook Api技术,因为需要硬编码,所以必须将结构 
压缩,将内容补齐! 
比如: 
ASM_STRUCT{ 
BYTE bJmp; 
DWORD dwDes; 
}a; 
如果不用Pack时,编译为: 
a.bJmp = 0xEB; // jmp的编码 
a.dwDes = 0x00410123; // jmp 0x00410123 
不用pack的话,内存内容为 0xEB XX XX XX 23 01 41 00 // 共8BYTE 
其中XX为不定值,用pack后 0xEB 23 01 41 00 // 共5BYTE 
这样,在Hook时运行这些指令,就必须用#parama pack(1) // 1 BYTE方式对齐。

如果直接把结构地址,以及结构长度,作为Send的参数发送整个结构,难道不需要pack吗?请教verybigbug()兄

不需要。 
send(struct, sizeof(struct));就可以了,如果两个程序都没有pack的话, 
相同的结构体在接收数据时就没有问题。必须保证两边的pack都是一样才行。 
我在写socket的程序(SDK方式)时送结构就从来不用pack的。 
只在写Hook Api时才用pack(1)。  

 

#pragma comment(lib, "ws2_32") 是什么意思 ???

.就相当于你将ws2_32.lib包含到工程中去。这样你就可以使用DLL接口函数了

 

#pragma data_seg 是什么意思??

用#pragma data_seg建立一个新的数据段并定义共享数据,其具体格式为: 

  #pragma data_seg ("shareddata") 

  HWND sharedwnd="NULL";//共享数据 

  #pragma data_seg()     // 再windows 核心编程思想中有很多地方用到。