#pragma 指令学习

在所有预处理命令当中,#pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或则指示编译
器完成一些特定的动作,#pragma 指令对每个编译器给出了一个方法,在保持与C 和C++语言完全兼容的
情况下,给出主机或操作系统专有的特征,依据定义,编译指示是机器或则操作系统专有的,且对每个
编译器都是不同的。

其格式一般是: #pragma paramenter 
其中: paramenter 是参数

(1) message 参数: 它能够在编译信息输出窗口中输出相应的信息,
这对于源代码信息的控制是非常重要的,使用方法是:

#pragma message("消息文本")
当编译器遇到这条指令的时候就在编译信息输出窗口输出相应的信息,把消息文本打印出来.
当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确设置这些宏,
此时我们可以用这条指令在编译的时候就进行检查,假设我们希望判断自己有没有在源代码的什么地方定义了 _X86这个
宏可以使用下面的方法:
#ifdef _X86
#pragma message("_X86 macro activited")
#endif

如果我们定义了_X86这个宏,应用程序在编译是就会在编译输出框显示:"_X86 macro activited",我们
就不会因为自己不记得是否定义而苦恼了.

(2) 另外一个使用得比较多的pragma  参数是code_seg 格式如:
#pragma code_seg ([[{push|pop},][identifier,]]["section-name"["sectin class"]])
它能够设置程序中函数代码存放的代码段(位置).(另注:该参数可以用来指定在*.obj 文件中存放的节,
观察 *.obj可以使用VC自带的dumpbin命令行程序,函数在*.obj文件中默认的存放字节是 .text节.
如果code_seg 没有带参数的话,则函数存放在 .text节
push [可选参数] 将一个记录放到内部编译器的堆栈中,可选参数 identifier可以是一个标识符或者节名.
pop [可选参数] 将一个记录从堆栈的顶端弹出,可选参数 identifier 可以为一个标识符或者节名.
可选参数 identifier,当使用PUSH指令时候,为压入堆栈的记录指派一个标识符,当该标识符被删除的时候和
其相关的堆栈中的记录将被弹出堆栈.
"segment-name" [可选参数] 表示函数存放的节名.
例如:
默认情况下,函数被存放在.text中,
void func1(){   //stored in .text
}

将函数存放到节 .my data中
#pragma code_seg(".my data1")
void func2()[ stored in my data
}

//r1为标志符,将函数放入.my data2节中
#pragma code_seg (push,r1,".my data2")
void func3(){ //stored in my data2
}

(3) #pragma once 这是一个比较常用的指令,只要在头文件的最开始加入这条指令就能够保证头文件被编译一次.
这条指令在VC6里面就有,要考虑到兼容性.

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

(5) #pragma warning 指令
该指令允许有选择性的修改编译器的警告信息行为.
指令格式:
#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)
#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)来消除该类型的警告信息


(6)#pragma comment(...)
#pragma comment("comment-type"[,commentstring])
该指令将一个注释记录放入一个对象文件或可执行文件中 comment-type 类型 one of the five
compiler:将编译器的版本号和名称放入目标文件中,本条注释记录将被编译器忽略,如果你为该记录类型
提供了commentstring 参数,编译器将产生一个警告,
EX: #pragma comment (compiler)

exestr:将commentstring 参数放入目标文件中,在链接的时候这个字符串将被放入到可执行文件中,当操
作系统加载可执行文件时,该参数字符串不会被加载到内存中,但是,该参数字符串可以被dumpbin之类的的
程序查找并打印出来,你可以用这个标志符号将版本之类的信息潜入到可执行文件中。

lib:这是一个非常常用的关键字,可以帮我们连入一个库文件到目标文件。
ex:
 #pragma comment(lib,"userlib.lib")

linker:
将一个链接选项放入目标文件中,你可以使用这个指令来代替命令行传入的或则在开发环境中设置的链接
选项,你可以指定/include 选项来强制包含某个对象
ex:
  #pragma comment(linker,"/include:_mySymbol")
你可以在程序中设置下列链接选项:
 /DEFAULTLIB
 /EXPORT
 /INCLUDE
 /MERGE
 /SECTION
详情请参考msdn

user: 将一般的注释信息放入目标文件中,commentstring 参数包含注释的文本信息,这个注释记录将被
链接器忽略。
ex:
 #pragma comment(user,"compiled on " _DATE" at "_TIMER_")

 

使用#pragma 导出 DLL 函数
传统的导出DLL函数的方法是使用模块定义文件(.def),Visual C++ 提供了更简洁方便的方法,那就
是"_declspec()" 关键字后面跟"dllexport",告诉链接去导出这个函数.
例如 :
 _declspec(dllexport) int _stdcall MyExportFunction(int iTest);
把"__declspec(dllexport)"放在最前面声明,连接生成的DLL 就会导出函数"_MyExportFunction@4".
上面导出的函数名称也许不是我们希望的,我们希望导出原版"的"MyExportFunction".  可以指定用VC
提供的"#pragma"指令来指定链接选项.
ex:
 #pragma comment(linker,"/EXPORT:MyExportFunction=_MyExportFunction@4")

原形:  /EXPORT:entryname[,@ordinal[,NONAME]][,DATA]
 @ordinal 指定顺序;NONAME 指定只将函数导出为序号;DATA关键字指定导出项为数据项.