C和C++的每个实现对它的主机或操作系统都支持一些独有的特征。例如, 某些程序须对存放数据的存储器区域进行精确的控制,或必须控制特定函数接受参量的方式。#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。
语法
#pragma 语言符号字符串
语言符号字符串是给出特有编译器指令和参量的字符序列。数字符号(#)必须是包含编译指示行中的第一个非空白字符。空白字符可分开数字符号(#)和单词pragma 。在#pragma之后,可以编写翻译器作为预处理器语言符号分析的任何文本。#pragma的参量从属于宏扩展。
如果编译器找到一个不能识别的编译指示,将发出一个警告,但编译将继续。编译指示可用在条件说明中,以提供新的预处理器功能,或提供定义的实现信息给编译器。C和C++编译器可识别下面的编译指示:
alloc_text comment init_seg* optimize
auto_inline component inline_depth pack
bss_seg data_seg inline_recursion pointers_to_members*
check_stack function intrinsic setlocale
code_seg hdrstop message vtordisp*
const_seg include_alias once warning*
仅被C++编译器支持
--------------------------------------------------------------------------------
C++编译器专有编译指示
以下是C++编译器专有的编译指示指令:
* init_segl
pointers_to_members
* vtordisp
init_seg
C++特殊处
#pragma init-seg({complier/lib/user/ "section-name" [,"func-name"]})该指令指定一个影响启动代码执行顺序的关键字或代码段。由于全局静态对象的初始化可能涉及执行代码,因此必须指定创建对象时定义的一个关键字。在动态连接库(DLL)或需初始化的库中使用init_seg编译指示尤其重要。
init_seg编译指示的选项如下:
complier
该选项保留给Microsoft C运行库初始化。这个组中的对象最先被创建。lib 用于第三方类库供应商的初始化。该组中的对象在complier标志之后,其他标记之前创建。
user
用于任何用户。此组对象最后创建。
section_name
允许初始化段的显示规格。在一个用户指定section-name(段名称)中的对象不能被隐含地创建,但它们的地址可放在以section_name命名的段中。
func_name
指定在程序退出时在exit()地方调用的函数。指定的函数必须与exit函数具有相同的特征:int funcname(void(__cdecl*)(void));
如果你需要延迟初始化过程(例如,在一个DLL中),你可以选择显式地指定该段名称。然后必须为每个静态对象调用构造函数。
C++特殊处结束
pointers_to_members
C++特殊处
#progma pointers_to_members(指针说明,[最一般表示])
该指令指定一个类成员的指针能否在其相关定义之前被说明,且用于控制该指针尺寸和解释该指针需要的代码。你可以把一个pointers_to_members编译指示放入你的源文件中替换/vmx编译器选项。
指针说明参量指定你在一个关联函数定义之前还是之后说明了一个成员的指针。指针说明参量是以下两个符号之一:
参量 说明
full_generality 生成安全、但常常并非最优的代码。如果在关联类定义之前说明任何成员的指针,可使用full_generality。该参量通常使用最一般表示参量指定的指针表示形式。等同于/vmg选项
best_case 为所有成员指针使用最佳情况(best__case)表示生成安全的最优代码。使用该参量是需在定义一个类的成员指针说明之前定义此类。其缺省值为best_case
best_case 为所有成员指针使用最佳情况(best__case)表示生成安全的最优代码。使用该参量是需在定义一个类的成员指针说明之前定义此类。其缺省值为best_case
最一般表示参量说明了在转换单元中,编译器能够安全地引用任何指向类成员的指针的最小指针表示。该参量取如下值之一:
参量 说明
single_inheritance 最一般表示是单继承的,即一个成员函数的指针。对于其中说明了一个指向成员指针的一个类定义,若其继承模式说明为多重的或虚拟的,将导致错误
multiple_inheritance 最一般表示是多重继承的,即一个成员函数的指针。对于其中说明了一个指向成员指针的一个类定义,若其继承模式是虚拟的,将导致错误
vitual_inheritance 最一般表示是虚拟继承,即一个成员函数的指针。该函数不会导致错误。当使用#pragma pointers_to_members(full_generality) 时这是个缺省参量
C++特殊处结束
vtordisp
C++特殊处
#pragma vtordisp({on|off})
该指令允许增加隐含的vtordisp构造函数/析构函数替换成员。vtordisp编译指示只使用虚基类的代码。若一个派生类重迭一个从虚拟基类继承的虚拟函数,且如果派生类的一个构造函数或析构函数调用那个使用该虚拟基类指针的函数,则编译器可能将增加的隐含“vtordisp”域到有虚拟基的类中。
vtordisp编译指示会影响其后类的分布。/Vd0或/Vd1选项指定了对于完全模式的相同动作。指定off将抑制隐含的vtordisp成员。指定缺省值on, 将在需要的位置打开它们。Vtordisp指令仅在类的构造/析构函数在用this 指针指向的对象处不可能调用虚拟函数时关闭。
#pragma vtordisp(off)
class GetReal:virtual public{...};
#pragma vtordisp(on)
C++特殊处结束
--------------------------------------------------------------------------------
C和C++编译器编译指示
以下是为C和C++编译器定义的编译指示:
alloc_text component init_seg* optimize
auto_inline const_seg inline_depth pack
bss_seg data_seg inline_recursi onpointers_to_members*
check_stack function intrinsic setlocale
code_seg hdrstop message vtordisp*
comment include_alias once warning
* 仅被C++编译器支持
alloc_text#pragma alloc_text(“文本段”,函数1,...)
该指令用于命名指定的函数定义将要驻留的代码段。该编译指示对已命名的函数必须出现在一个函数说明符和该函数定义之间。
alloct_text编译指示并不处理C++成员函数或重载函数。它仅用于以C连接方式说明的函数,这指的是用extern“C”连接规格说明的函数。如果你试图将此编译指示用于非C++连接的函数,将产生一个编译错误。
由于不支持使用__based的函数地址,指定段位址需要使用alloc_text编译指示,以文本段指定的名称应包括在双引号间。
alloc_text编译指示必须出现在指定的函数说明之后,这些函数的定义之前。一个alloc_text编译指示中的函数引用必须在此编译指示的同一模块中定义。如果未这样做,且一个未定义的函数随后被编译到一个不同的文本段,则这个错误可能找得到,也可能找不到。虽然该程序一般会正常运行,但该函数不会分配到预期的段中。
alloc_text的其他限制如下:
* 它不能用在一个函数的内部。
* 它必须在已说明的函数之后和已定义的函数之前使用。
auto_inline
#pragma auto_inline([{on|off}])
排除自动内联扩展的候选者中指定为off的区域中定义的函数。为了使用auto_inline编译指示,把它放在一个函数定义之前或立即之后(不在该函数定义之内)。在看到该编译指示之后的第一个函数定义处,该编译指示发生作用。编译指示auto_inline不能应用于显式内联函数。
bss_
seg#pragma data-seg(["section-name"[,"section-class"]])
指定未初始化数据的缺省段。data_seg编译指示处理初始化或未初始化数据有相同的作用。在某些情况下,你可以使用bss_seg通过把所有未初始化数据放在一个段中来加速加载的时间。
#pragma bss_seg("MY_DATA")
导致#pragma语句后未初始化的数据分配到一个名称为MY_DATA的段中。
用bss_seg编译指示分配的数据不会保留关于它的位置的任何信息。
第二个参量section_class用于与Visual C++之前的版本兼容,现在已被忽略。
check_stack
#pragma check_stack([{on|off}])
#pragma check_stack{+|-}
该指令在off(或-)选项时指示编译器关闭栈搜索。在on(或+)选项指定时,打开搜索。
若无参量,栈搜索就按缺省情况处理。在看到该编译指示之后第一个定义的函数处发生作用。栈搜索既不是宏的一部分,也不是产生的内联函数的一部分。
如果未赋予一个参量给check_stack编译指示,栈检查将还原成在命令行中说明的行为,有关更多的信息参见“编译器参考”。#pragma check_stack和/Gs选项的交互关系参见表2.1。
表2.1 使用check_stack编译指示
语法 是否用/Gs选项编译 行为
#pragma check_stack()或#pragma check_stack 是 关闭其后函数的栈检查
#pragma check_stack()或#pragma check_stack 否 打开其后函数的栈检查
#pragma check_stack(on)或#pragma check_stack + 是或否 打开其后函数的栈检查
#pragma check_stack(off)或#pragma check_stack - 是或否 关闭其后函数的栈检查
code_seg
#pragma code_seg(["section-name"[,"section-class"]])
该指令用于指定一个分配函数的代码段。code_seg编译指示指定了函数的缺省段。
你可以有选择性地指定类和段名。使用没有section-name字符串的#pragmacode_seg可在编译开始时将其复位。
const_seg
#pragma const_seg(["section-name"[,"section-class"]])
该指令用于指定对于常量数据的缺省段。data_seg编译指示对所有数据具有相同作用。你可以用此指令将你的所有常量数据放入一个只读段中。
#pragma const_seg("MY_DATA")
导致该指令将#pragma语句后的常量数据放入一个名称为MY_DATA的段里。
使用const_seg编译指示分配的数据不会保留有关它的位置的任何信息。
第二个参数section-class用于与Visual C++ 2.0版之前的版本兼容,现在已可忽略。
comment
#pragma comment(comment-type,[commentstring])
该指令将一个注释记录放入一个对象文件或可执行文件中。comment-type是下面五种说明的预定义标识符之一,它们指出了注释记录的类型。任选的commentstring是给一些注释类型提供额外信息的字符串文字。由于commentstring是一个字符串文字, 因此它必须遵循对于字符串文字的诸如转义字符、嵌lib
该选项将一个库搜索记录放入对象文件。该注释类型必须带有一个commentstring参数。这个参数包含你想要的链接器搜索的库的名称(有可能包含路径)。由于在对象文件中该库名称在缺省的库搜索记录之前,所以链接器搜索该库就象你在命令行中命名了它一样。你可以把多个库搜索记录放在同一个源文件中,每个记录在对象文件中都以其在源文件中出现的同样顺序出现。
linker
该选项将一个链接器选项放入对象文件中。可以用该注释类型指定一个链接器选项,用于取代在Project Setting对话框中Link选项卡上放入该选项。例如,你可以指定/include选项来强行包括一个符号:
#pragma comment(linker,"/include:__symbol")
user
该选项将一个一般的注释放入对象文件中。commentstring参量包含了该注释的文本。这个注释记录被链接器忽略。
以下编译指示导致链接器在连接时搜索EMAPI.LIB库。 该连接器首先在当前工作目录中搜索,随后在LIB环境变量说明的路径中搜索。
#pragma comment(lib,"emapi")
以下编译指示导致编译器把编译器的名称和版本号放入对象文件:
#pragma comment(complier)
注意:对于一个带commentstring参量的注释, 你可以在任何要使用一个字符串文字的地方使用宏,让这个宏扩展为一个字符串文字。你也可以把任何一个字符串文字的任何组合与扩展为字符串文字的宏合并起来,例如:下面的语句是可以接受的:
#pragma comment(user,"Compiled on" __DATA_ _ "at" _ _TIME_ _)
component#pragma
component(browser,{on|off}[,references[,name]])#pragma component(minrebuild,on|off)
该指令用于控制源文件内的浏览信息或依赖信息的集合。
browser
你可以打开或关闭集合,并可以在收集信息时指定忽略的特定名称。
用on或off选项控制前面编译指示的浏览信息的集合。例如:
#pragma component(browser,off)
该指令让编译器停止收集浏览信息。
注意:用此指令打开浏览信息的集合,浏览信息必须先用Project Settings对话框或命令行打开。
references选项可带也可不带name参量。不带name参量的references选项用于打开或关闭引用的集合(但此时继续收集其它浏览信息)。例如:
#pragma component(browser,off,references)
该指令使编译器停止收集引用信息。
带name和off参量的references选项,用于防止浏览信息窗口中出现对name的引用。使用这种语法可忽略你不感兴趣的名称和类型, 并且可缩短浏览信息的尺寸。例如:
#pragma component(browser,off,references,DWORD)
忽略该点之前对于DWORD的引用。但你可用on选项把对于DWORD引用的集合重新打开。
#pragma component(browser,on,references,DWORD)
这是恢复对name引用集合唯一的方式;用此方式你可以显式地打开任何你已经关闭的name。
为了防止预处理器把name展开(如把NULL扩展为0),将它加上引号:
#pragma component(browser,off,references,"NULL")
Minimal Rebuild
Visual C++的minimal rebuild(最小重建)特性需要编译器创建和存储依赖信息的C++类,这将占用磁盘空间。为了节省磁盘空间,你可以在任何你不需收集依赖信息的时候仅用#pragma component(minirebuild,off),例如,在不变的头文件中。在不变的类后插入#pragma component(minrebuild,on)可重新打开依赖信息。
有关更多的信息参见Enable Minimal Rebuild(/Gm)编译器选项。
data_seg
#pragma data_seg(["section-name"[,"section-class"]])
该指令指定数据的缺省段。例如:
#pragma data_seg("MY_DATA")
将#pragma语句后分配的数据放在以名称为MY_DATA的段里。
使用data_seg编译指示分配的数据不会保留关于它的位置的任何信息。
第二个参量section-class用于与Visual C++ 2.0之前的版本兼容,现在已可忽略。
function
#pragma function(function1[,function2,...])
该指令指定对在生成的编译器编译指示参量表中指定调用的函数。如果你使用intrinsic编译指示(或/Oi)告诉编译器生成内在函数(被生成为内联代码,而非函数调用的内在函数),就能用function编译指示来显式地强制调用一个函数。当一个函数编译指示出现时,它在第一个包含一个指定的内在函数的函数定义处发生作用,这个作用持续到源文件的结尾或直到一个说明这种相同的内在函数的编译指示出现为止。在全局层时,该function编译指示只能用在一个函数外。对于具有内部形式的函数表,参见#pragma intrinsic。
hdrstop
#pragma hdrstop[("filename")]
该指令用于控制预编译头文件的工作方式。filename是预编译头文件使用或创建的名称(根据指定选项/Yu或/Yc决定)。如果filename不包含路径说明,预编译头文件将被假定在与源文件相同的目录中。当指定/YX自动预编译头文件选项时,所有filename都被忽略。
当采用/YX或/Yc编译时,一个C或C++文件包含一个hdrstop编译指示,该编译器将把编译状态存入到编译指示的位置。该编译指示之后任何代码的编译状态都不存储。
hdrstop编译指示不可能出现在一个头文件中。它必须出现在源文件中。这指的是,它不能出现在任何数据、函数说明或函数定义中。
注意:除非/YX选项或无文件名的/Yu或/Yc选项被指定,否则hdrstop编译指示将被忽略。
该指令使用filename命名编译状态存储的预编译头文件。hdrstop和filename之间的一个空白是任选的。在hdrstop编译指示中说明的文件名称是一个字符串, 而且必须服从C或C++字符串的约束。尤其重要的是必须将其置于括号中
如下例所示:
#pragma hdrstop("c:/projects/include/myinc.pch")
预编译头文件的名称由下列规则决定,顺序如下:
1. /Fp编译器选项的参量。
2. #pragma hdrstop的filename参量。
3. 以.PCH为扩展名的源文件的基名称。
include_alias
#pragma include_alias("long_filename","short_filename")
#pragma include_alias(,)
该指令指定short_filename作为long_filename的别名。某些文件系统允许比8.3 FAT文件系统限定更长的文件名。编译器不能够简单地把更长的头文件名截短为8.3格式,因为这种更长的头文件名的开始八个字符可能不是唯一的。只要编译器遇到long_filename字符串,就用short_filename替换,并且代替查找short_filename头文件。这个编译指示必须出现在相应的#include指令之前,
例如:/
/这两个文件的开头八个字符不是唯一的
#pragma include_alias("AppleSystemHeaderQuickdraw.h","quickdra.h")
#pragma include_alias("AppleSystemHeaderFruit.h","fruit.h")
#pragma include_alias( "GraphicsMenu.h", "gramenu.h")
#include "AppleSystemHeaderQuickdraw.h"
#include "AppleSystemHeaderFruit.h"
#include "GraphicsMenu.h"
无论是拼写,还是双引号或尖括号的用法,被搜索的别名都必须符合规格。include_alias编译指示在该文件名中处理简单的字符串匹配,而在其它的文件名中是无效的。例如,给出如下指令:
#pragma include_alias("mymath.h","math.h")
#include "./mymath.h"
#include "sys/mymath.h"
没有别名使用(替换)被执行,因为头文件字符串并不匹配。用作/Yu、/Yc和/YX编译器选项参量的头文件名,或hdrstop编译指示的头文件名也不能被替换。例如,若你的源文件包含下列指令:
#include
相应的编译器选项应该是:
/YcAppleSystemHeaderStop.h
你可以用include_alias编译指示把任何头文件名映射为另一个。例如:
#pragma include_alias("api.h", "c:/version1.0/api.h")
#pragma include_alias(, )
#include "api.h"
#include
不要把双引号内的文件名和尖括号内的文件名相混淆,例如,对于上面给出的两个#pragma include_alias指令,编译器在下面的#include指令中不执行任何替换:
#include
Include "stdio.h"
此外,下面的指令将导致错误:
#pragma include_alias(,"header.h") //错误
注意在错误信息中给出的文件名,或作为预先定义的__FILE__宏的值,是替换执行之后的文件的名称,例如,下面指令后:
#pragma include_alias("VeryLongFileName.H","myfile.h" )
#include "VeryLongFileName.H"
在VERYLONGFILENAME.H中的一个错误将导致如下错误消息:
myfile.h(15) : error c2059 : syntax error
同时注意传递性是不支持的。如下指令中:
#pragma include_alias( "one.h", "two.h" )
#pragma include_alias( "two.h", "three.h")
#include "one.h"编译器搜索的是文件TWO.H而不是THREE.H。
inline_depth
#pragma inline_depth([0...255])
该指令通过控制一系列函数调用能被扩展的次数(从0到255次),来控制内联扩展可发生的次数。这个编译指示控制标记为inline和_ _inline的函数的联编或在/Ob2选项下已经自动联编的函数。
inline_depth编译指示控制一序列函数调用能被扩展的次数,例如,若联编深度为4,且若A调用B,B调用C,三个调用都将内联扩展。但如果最近的内联扩展为2,只有A和B被扩展,C保留为一个函数调用。
为使用这个编译指示,你必须设置/Ob编译器选项为1或2。使用这个编译指示的深度设置在该编译指示指令后的第一个函数处生效。如果你没有在圆括号中指定一个值,inline_depth将设置联编深度为缺省值8。
联编深度在扩展时只减不增。若联编深度为6,且在扩展时,预处理器遇到一个联编深度值为8的inline_depth编译指示,该深度仍保持为6。
联编深度0禁止联编扩展;联编深度255对联编扩展无限制,若使用一个未指定其值的编译指示,则将使用其缺省值。
inline_recursion
#pragma inline_recursion([{on|off}])
该指令控制直接或相互递归函数调用的联编扩展。该指令用于控制标记为inline和_ _inline的函数,或编译器在Ob2选项下自动扩展的函数。这个编译指示的用法需要一个设置为1或2的/Ob编译器选项。inline_recursion的缺省状态是off。这个编译指示只是在其出现之后的第一个函数处起作用,并且不会影响该函数的定义。
inline_recursion编译指示控制递归函数如何被扩展。如果inline_recursion关闭,且若一个联编函数调用其自身(直接或间接),该函数只被扩展一次。若inline_recursion为打开状态,则该函数将被扩展多以下所列的浮点函数没有真正的内在格式。但它们有这样的版本:将参量直接送入浮点芯片,而不是将它们压入程序栈中:
acos cosh pow tanh
asin fmod sinh
当你指定/Oi和/Og编译器选项(或任何包括/Og、/Ox、/O1和/O2的选项)时,以下浮点函数有真正的内在格式:
atan exp log10 sqrt
atan2 log sin tan
cos
你可以使用/Op或/Za编译器选项重迭真正的内在浮点选项的生成。这种情况下,该函数被生成为库例程,该例程直接把参量送入浮点芯片,而不是把它们压入程序栈。
message
#pragma message(messagestring)
该指令不终止编译,直接把一个字符串文字送到标准输出。message编译指示的典型用法是在编译时显示信息消号。以下代码段使用message编译指示在编译时显示一个消息:
#if _M_IX86==500
#pragma
message("Pentium processor build")#endifmessagestring参数可以是可扩展为一个字符串文字的宏,并且你可以以任何组合方式用字符串文字将这些宏合并起来。例如,下列语句显示了被编译的文件名以及该文件最后改动的日期和时间:
#pragma message("Compiling "__FILE__ )
#pragma message("Last modified on " __TIMESTAMP_ _)
once
#pragma once
该指令指定该编译指示驻留的文件将只在一次建立中被编译器包括(打开)一次。该编译指示的一种普通用法如下:
//header.h
#pragma once
//接着是你的C或C++代码
optimize
#pragma optimize( "[optimization-list]",{on|off} )
仅用于专业和企业版本的特征:代码优化只被Visual C++专业版和企业版支持。更多的信息参见Microsoft Visual C++联机编辑。
该指令指定在函数基中执行的优化。optimize编译指示必须出现在一个函数之外,并且在编译指示出现后定义的第一个函数处产生作用。on和off参量可以打开或关闭在Optimization-list中指定的选项。
optimization-list可以是0或在表2.2中给出参数。
表2.2 "优化"编译指示的参数
参量 优化类型
a 假定无别名
g 允许全局优化
p 提高浮点相容性
s或t 指定机器码的短或快序列
w 假定无交叉函数调用的别名
y 生成程序堆栈中的框架指针
这些是采用/O编译器选项的相同字母,例如:
#pragma optimize("atp", on)
用空字符串("")使用optimize编译指示是该指令的一种特殊形式,它可关闭所有的优化或恢复它们的原有(缺省的)设置。
#pragma optimize("",off)
...
#pragma optimize("", on)
pack
#pragma pack([n])
该指令指定结构和联合成员的紧凑对齐。而一个完整的转换单元的结构和联合
的紧凑对齐由/Zp选项设置。紧凑对齐用pace编译指示在数据说明层设置。该编译指示在其出现后的第一个结构或联合说明处生效。该编译指示对定义无效。当你使用#pragma pack(n)时,这里n为1、2、4、8或16。第一个结构成员之后的每个结构成员都被存储在更小的成员类型或n字节界限内。如果你使用无参量的#pragma pack,结构成员被紧凑为以/Zp指定的值。该缺省/Zp紧凑值为/Zp8。
编译器也支持以下增强型语法:
#pragma pack([[{push|pop},][标识符,]][n])
若不同的组件使用pack编译指示指定不同的紧凑对齐,这个语法允许你把程序组件组合为一个单独的转换单元。
带push参量的pack编译指示的每次出现将当前的紧凑对齐存储到一个内部编译器堆栈中。编译指示的参量表从左到右读取。如果你使用push,则当前紧凑值被存储起来;如果你给出一个n的值,该值将成为新的紧凑值。若你指定一个标识符,即你选定一个名称,则该标识符将和这个新的的紧凑值联系起来。
带一个pop参量的pack编译指示的每次出现都会检索内部编译器堆栈顶的值,并且使该值为新的紧凑对齐值。如果你使用pop参量且内部编译器堆栈是空的,则紧凑值为命令行给定的值,并且将产生一个警告信息。若你使用pop且指定一个n的值,该值将成为新的紧凑值。
若你使用pop且指定一个标识符, 所有存储在堆栈中的值将从栈中删除,直到找到一个匹配的标识符,这个与标识符相关的紧凑值也从栈中移出,并且这个仅在标识符入栈之前存在的紧凑值成为新的紧凑值。如果未找到匹配的标识符,将使用命令行设置的紧凑值,并且将产生一个一级警告。缺省紧凑对齐为8。
pack编译指示的新的增强功能让你编写头文件,确保在遇到该头文件的前后的紧凑值是一样的。
/* File name: include1.h*/
#pragma pack(push,enter_include1)
/* 你的包括文件代码... */
#pragma pack(pop, enter_include1)
/* include1.h结束 */
在上面的例子中,当前紧凑值与标识符enter_include1联系起来,并被压入头文件的项中。头文件末尾的pack编译指示删除所有可能出现在头文件中的干预紧凑值,并且删除与enter_include1相关的紧凑值。因此确保该头文件的前后的紧凑值是相同的。
这种新功能也允许你使用代码,例如头文件,它可以使用pack编译指示设置不同于在你的代码中设置的紧凑值的紧凑对齐:
#pragma pack(push,before_include1)
#include "include1.h"
#pragma pack( pop,before_include1)
在上面的例子中,对于出现在include.h中的紧凑值的任何变化,你的代码是受到保护的。
setlocale
#pragma setlocale("locale_string")
该指令在翻译宽字符常量和字符串文字时定义其场所(国家和语言)。由于用于转换多字节字符为宽位字符的算法可能由于场所或编译而不同,该执行文件在不同的场所运行也可能不同。这个编译指示提供了在编译时给出目标场所的方法。这保证了宽字符串以正确的格式进行存储。缺省的locale_ _string(场所字符串)是 “C”。“C”场所将每个该串中的字符映射为一个wchar_t(unsigned short)型的值。
warning
#pragma warning( warning-specifier:warning-number-list
[,warning-specifier:warning-number-list...])
#pragma warning(push[,n])#pragma warning(pop)
该指令允许选择性地改变编译器的警告消息。
warning-specifier可以是如下值之一:
警告指示符 含义
once 只显示一次指定的消息default将缺省的编译器行为应用于指定的消息
1,2,3,4 把给定的警告级应用于指定的警告消息
disable 不发出指定警告消息
error 作为错误报告指定的警告
warning-number-list(警告编号表)可以包含任何警告编号。在相同的编译指示指令中可指定多个选项如下:
#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
对于那些与代码生成有关,且大于4699的警告编号来说,这个warning编译指示仅当放在函数定义外时有效。如果警告编号大于4699或用在函数体内,则忽略该编译指示。下面的例子指出了禁止warning编译指示的正确位置,且随后恢复一个代码生成警告消息的产生。
int a;
#pragma warning( disable : 4705 )
void func()
{
a;
}
#pragma warning( default : 4705 )
warning编译指示也支持以下语法:
#pragma warning( push[,n])
#pragma warning( pop)
这里n代表警告级(1到4)。
编译指示warning(push)存储所有警告的当前警告状态。编译指示warning(push,n)存储所有警告的当前警告状态并设置全局警告级为n。
编译指示warning(pop)将上次压入栈的警告状态弹出,push和pop之间警告状态的任何变化都将被取消。考虑这个例子:
#pragma warning(push)
#pragma warning(disable : 4705)
#pragma warning(disable : 4706)
#pragma warning(disable : 4707)
// 某些代码
#pragma warning(pop)
在这段代码的未尾,pop恢复所有警告状态(包括4705、4706和4707)为它在代码起始处的警告状态。
当你编写头文件时,可以用push和pop以确保对于用户造成的警告状态的变化,不会影响头部的正确编译。通常在头部的起始处使用push,在末尾处使用pop。例如, 有一个在警告级4未彻底编译的头部。以下代码将警告级改为3,然后在头部的未尾恢复原来的警告级:
#pragma warning(push,3)
//说明/定义
#pragma warning(pop)
语法
#pragma 语言符号字符串
语言符号字符串是给出特有编译器指令和参量的字符序列。数字符号(#)必须是包含编译指示行中的第一个非空白字符。空白字符可分开数字符号(#)和单词pragma 。在#pragma之后,可以编写翻译器作为预处理器语言符号分析的任何文本。#pragma的参量从属于宏扩展。
如果编译器找到一个不能识别的编译指示,将发出一个警告,但编译将继续。编译指示可用在条件说明中,以提供新的预处理器功能,或提供定义的实现信息给编译器。C和C++编译器可识别下面的编译指示:
alloc_text comment init_seg* optimize
auto_inline component inline_depth pack
bss_seg data_seg inline_recursion pointers_to_members*
check_stack function intrinsic setlocale
code_seg hdrstop message vtordisp*
const_seg include_alias once warning*
仅被C++编译器支持
--------------------------------------------------------------------------------
C++编译器专有编译指示
以下是C++编译器专有的编译指示指令:
* init_segl
pointers_to_members
* vtordisp
init_seg
C++特殊处
#pragma init-seg({complier/lib/user/ "section-name" [,"func-name"]})该指令指定一个影响启动代码执行顺序的关键字或代码段。由于全局静态对象的初始化可能涉及执行代码,因此必须指定创建对象时定义的一个关键字。在动态连接库(DLL)或需初始化的库中使用init_seg编译指示尤其重要。
init_seg编译指示的选项如下:
complier
该选项保留给Microsoft C运行库初始化。这个组中的对象最先被创建。lib 用于第三方类库供应商的初始化。该组中的对象在complier标志之后,其他标记之前创建。
user
用于任何用户。此组对象最后创建。
section_name
允许初始化段的显示规格。在一个用户指定section-name(段名称)中的对象不能被隐含地创建,但它们的地址可放在以section_name命名的段中。
func_name
指定在程序退出时在exit()地方调用的函数。指定的函数必须与exit函数具有相同的特征:int funcname(void(__cdecl*)(void));
如果你需要延迟初始化过程(例如,在一个DLL中),你可以选择显式地指定该段名称。然后必须为每个静态对象调用构造函数。
C++特殊处结束
pointers_to_members
C++特殊处
#progma pointers_to_members(指针说明,[最一般表示])
该指令指定一个类成员的指针能否在其相关定义之前被说明,且用于控制该指针尺寸和解释该指针需要的代码。你可以把一个pointers_to_members编译指示放入你的源文件中替换/vmx编译器选项。
指针说明参量指定你在一个关联函数定义之前还是之后说明了一个成员的指针。指针说明参量是以下两个符号之一:
参量 说明
full_generality 生成安全、但常常并非最优的代码。如果在关联类定义之前说明任何成员的指针,可使用full_generality。该参量通常使用最一般表示参量指定的指针表示形式。等同于/vmg选项
best_case 为所有成员指针使用最佳情况(best__case)表示生成安全的最优代码。使用该参量是需在定义一个类的成员指针说明之前定义此类。其缺省值为best_case
best_case 为所有成员指针使用最佳情况(best__case)表示生成安全的最优代码。使用该参量是需在定义一个类的成员指针说明之前定义此类。其缺省值为best_case
最一般表示参量说明了在转换单元中,编译器能够安全地引用任何指向类成员的指针的最小指针表示。该参量取如下值之一:
参量 说明
single_inheritance 最一般表示是单继承的,即一个成员函数的指针。对于其中说明了一个指向成员指针的一个类定义,若其继承模式说明为多重的或虚拟的,将导致错误
multiple_inheritance 最一般表示是多重继承的,即一个成员函数的指针。对于其中说明了一个指向成员指针的一个类定义,若其继承模式是虚拟的,将导致错误
vitual_inheritance 最一般表示是虚拟继承,即一个成员函数的指针。该函数不会导致错误。当使用#pragma pointers_to_members(full_generality) 时这是个缺省参量
C++特殊处结束
vtordisp
C++特殊处
#pragma vtordisp({on|off})
该指令允许增加隐含的vtordisp构造函数/析构函数替换成员。vtordisp编译指示只使用虚基类的代码。若一个派生类重迭一个从虚拟基类继承的虚拟函数,且如果派生类的一个构造函数或析构函数调用那个使用该虚拟基类指针的函数,则编译器可能将增加的隐含“vtordisp”域到有虚拟基的类中。
vtordisp编译指示会影响其后类的分布。/Vd0或/Vd1选项指定了对于完全模式的相同动作。指定off将抑制隐含的vtordisp成员。指定缺省值on, 将在需要的位置打开它们。Vtordisp指令仅在类的构造/析构函数在用this 指针指向的对象处不可能调用虚拟函数时关闭。
#pragma vtordisp(off)
class GetReal:virtual public{...};
#pragma vtordisp(on)
C++特殊处结束
--------------------------------------------------------------------------------
C和C++编译器编译指示
以下是为C和C++编译器定义的编译指示:
alloc_text component init_seg* optimize
auto_inline const_seg inline_depth pack
bss_seg data_seg inline_recursi onpointers_to_members*
check_stack function intrinsic setlocale
code_seg hdrstop message vtordisp*
comment include_alias once warning
* 仅被C++编译器支持
alloc_text#pragma alloc_text(“文本段”,函数1,...)
该指令用于命名指定的函数定义将要驻留的代码段。该编译指示对已命名的函数必须出现在一个函数说明符和该函数定义之间。
alloct_text编译指示并不处理C++成员函数或重载函数。它仅用于以C连接方式说明的函数,这指的是用extern“C”连接规格说明的函数。如果你试图将此编译指示用于非C++连接的函数,将产生一个编译错误。
由于不支持使用__based的函数地址,指定段位址需要使用alloc_text编译指示,以文本段指定的名称应包括在双引号间。
alloc_text编译指示必须出现在指定的函数说明之后,这些函数的定义之前。一个alloc_text编译指示中的函数引用必须在此编译指示的同一模块中定义。如果未这样做,且一个未定义的函数随后被编译到一个不同的文本段,则这个错误可能找得到,也可能找不到。虽然该程序一般会正常运行,但该函数不会分配到预期的段中。
alloc_text的其他限制如下:
* 它不能用在一个函数的内部。
* 它必须在已说明的函数之后和已定义的函数之前使用。
auto_inline
#pragma auto_inline([{on|off}])
排除自动内联扩展的候选者中指定为off的区域中定义的函数。为了使用auto_inline编译指示,把它放在一个函数定义之前或立即之后(不在该函数定义之内)。在看到该编译指示之后的第一个函数定义处,该编译指示发生作用。编译指示auto_inline不能应用于显式内联函数。
bss_
seg#pragma data-seg(["section-name"[,"section-class"]])
指定未初始化数据的缺省段。data_seg编译指示处理初始化或未初始化数据有相同的作用。在某些情况下,你可以使用bss_seg通过把所有未初始化数据放在一个段中来加速加载的时间。
#pragma bss_seg("MY_DATA")
导致#pragma语句后未初始化的数据分配到一个名称为MY_DATA的段中。
用bss_seg编译指示分配的数据不会保留关于它的位置的任何信息。
第二个参量section_class用于与Visual C++之前的版本兼容,现在已被忽略。
check_stack
#pragma check_stack([{on|off}])
#pragma check_stack{+|-}
该指令在off(或-)选项时指示编译器关闭栈搜索。在on(或+)选项指定时,打开搜索。
若无参量,栈搜索就按缺省情况处理。在看到该编译指示之后第一个定义的函数处发生作用。栈搜索既不是宏的一部分,也不是产生的内联函数的一部分。
如果未赋予一个参量给check_stack编译指示,栈检查将还原成在命令行中说明的行为,有关更多的信息参见“编译器参考”。#pragma check_stack和/Gs选项的交互关系参见表2.1。
表2.1 使用check_stack编译指示
语法 是否用/Gs选项编译 行为
#pragma check_stack()或#pragma check_stack 是 关闭其后函数的栈检查
#pragma check_stack()或#pragma check_stack 否 打开其后函数的栈检查
#pragma check_stack(on)或#pragma check_stack + 是或否 打开其后函数的栈检查
#pragma check_stack(off)或#pragma check_stack - 是或否 关闭其后函数的栈检查
code_seg
#pragma code_seg(["section-name"[,"section-class"]])
该指令用于指定一个分配函数的代码段。code_seg编译指示指定了函数的缺省段。
你可以有选择性地指定类和段名。使用没有section-name字符串的#pragmacode_seg可在编译开始时将其复位。
const_seg
#pragma const_seg(["section-name"[,"section-class"]])
该指令用于指定对于常量数据的缺省段。data_seg编译指示对所有数据具有相同作用。你可以用此指令将你的所有常量数据放入一个只读段中。
#pragma const_seg("MY_DATA")
导致该指令将#pragma语句后的常量数据放入一个名称为MY_DATA的段里。
使用const_seg编译指示分配的数据不会保留有关它的位置的任何信息。
第二个参数section-class用于与Visual C++ 2.0版之前的版本兼容,现在已可忽略。
comment
#pragma comment(comment-type,[commentstring])
该指令将一个注释记录放入一个对象文件或可执行文件中。comment-type是下面五种说明的预定义标识符之一,它们指出了注释记录的类型。任选的commentstring是给一些注释类型提供额外信息的字符串文字。由于commentstring是一个字符串文字, 因此它必须遵循对于字符串文字的诸如转义字符、嵌lib
该选项将一个库搜索记录放入对象文件。该注释类型必须带有一个commentstring参数。这个参数包含你想要的链接器搜索的库的名称(有可能包含路径)。由于在对象文件中该库名称在缺省的库搜索记录之前,所以链接器搜索该库就象你在命令行中命名了它一样。你可以把多个库搜索记录放在同一个源文件中,每个记录在对象文件中都以其在源文件中出现的同样顺序出现。
linker
该选项将一个链接器选项放入对象文件中。可以用该注释类型指定一个链接器选项,用于取代在Project Setting对话框中Link选项卡上放入该选项。例如,你可以指定/include选项来强行包括一个符号:
#pragma comment(linker,"/include:__symbol")
user
该选项将一个一般的注释放入对象文件中。commentstring参量包含了该注释的文本。这个注释记录被链接器忽略。
以下编译指示导致链接器在连接时搜索EMAPI.LIB库。 该连接器首先在当前工作目录中搜索,随后在LIB环境变量说明的路径中搜索。
#pragma comment(lib,"emapi")
以下编译指示导致编译器把编译器的名称和版本号放入对象文件:
#pragma comment(complier)
注意:对于一个带commentstring参量的注释, 你可以在任何要使用一个字符串文字的地方使用宏,让这个宏扩展为一个字符串文字。你也可以把任何一个字符串文字的任何组合与扩展为字符串文字的宏合并起来,例如:下面的语句是可以接受的:
#pragma comment(user,"Compiled on" __DATA_ _ "at" _ _TIME_ _)
component#pragma
component(browser,{on|off}[,references[,name]])#pragma component(minrebuild,on|off)
该指令用于控制源文件内的浏览信息或依赖信息的集合。
browser
你可以打开或关闭集合,并可以在收集信息时指定忽略的特定名称。
用on或off选项控制前面编译指示的浏览信息的集合。例如:
#pragma component(browser,off)
该指令让编译器停止收集浏览信息。
注意:用此指令打开浏览信息的集合,浏览信息必须先用Project Settings对话框或命令行打开。
references选项可带也可不带name参量。不带name参量的references选项用于打开或关闭引用的集合(但此时继续收集其它浏览信息)。例如:
#pragma component(browser,off,references)
该指令使编译器停止收集引用信息。
带name和off参量的references选项,用于防止浏览信息窗口中出现对name的引用。使用这种语法可忽略你不感兴趣的名称和类型, 并且可缩短浏览信息的尺寸。例如:
#pragma component(browser,off,references,DWORD)
忽略该点之前对于DWORD的引用。但你可用on选项把对于DWORD引用的集合重新打开。
#pragma component(browser,on,references,DWORD)
这是恢复对name引用集合唯一的方式;用此方式你可以显式地打开任何你已经关闭的name。
为了防止预处理器把name展开(如把NULL扩展为0),将它加上引号:
#pragma component(browser,off,references,"NULL")
Minimal Rebuild
Visual C++的minimal rebuild(最小重建)特性需要编译器创建和存储依赖信息的C++类,这将占用磁盘空间。为了节省磁盘空间,你可以在任何你不需收集依赖信息的时候仅用#pragma component(minirebuild,off),例如,在不变的头文件中。在不变的类后插入#pragma component(minrebuild,on)可重新打开依赖信息。
有关更多的信息参见Enable Minimal Rebuild(/Gm)编译器选项。
data_seg
#pragma data_seg(["section-name"[,"section-class"]])
该指令指定数据的缺省段。例如:
#pragma data_seg("MY_DATA")
将#pragma语句后分配的数据放在以名称为MY_DATA的段里。
使用data_seg编译指示分配的数据不会保留关于它的位置的任何信息。
第二个参量section-class用于与Visual C++ 2.0之前的版本兼容,现在已可忽略。
function
#pragma function(function1[,function2,...])
该指令指定对在生成的编译器编译指示参量表中指定调用的函数。如果你使用intrinsic编译指示(或/Oi)告诉编译器生成内在函数(被生成为内联代码,而非函数调用的内在函数),就能用function编译指示来显式地强制调用一个函数。当一个函数编译指示出现时,它在第一个包含一个指定的内在函数的函数定义处发生作用,这个作用持续到源文件的结尾或直到一个说明这种相同的内在函数的编译指示出现为止。在全局层时,该function编译指示只能用在一个函数外。对于具有内部形式的函数表,参见#pragma intrinsic。
hdrstop
#pragma hdrstop[("filename")]
该指令用于控制预编译头文件的工作方式。filename是预编译头文件使用或创建的名称(根据指定选项/Yu或/Yc决定)。如果filename不包含路径说明,预编译头文件将被假定在与源文件相同的目录中。当指定/YX自动预编译头文件选项时,所有filename都被忽略。
当采用/YX或/Yc编译时,一个C或C++文件包含一个hdrstop编译指示,该编译器将把编译状态存入到编译指示的位置。该编译指示之后任何代码的编译状态都不存储。
hdrstop编译指示不可能出现在一个头文件中。它必须出现在源文件中。这指的是,它不能出现在任何数据、函数说明或函数定义中。
注意:除非/YX选项或无文件名的/Yu或/Yc选项被指定,否则hdrstop编译指示将被忽略。
该指令使用filename命名编译状态存储的预编译头文件。hdrstop和filename之间的一个空白是任选的。在hdrstop编译指示中说明的文件名称是一个字符串, 而且必须服从C或C++字符串的约束。尤其重要的是必须将其置于括号中
如下例所示:
#pragma hdrstop("c:/projects/include/myinc.pch")
预编译头文件的名称由下列规则决定,顺序如下:
1. /Fp编译器选项的参量。
2. #pragma hdrstop的filename参量。
3. 以.PCH为扩展名的源文件的基名称。
include_alias
#pragma include_alias("long_filename","short_filename")
#pragma include_alias(,)
该指令指定short_filename作为long_filename的别名。某些文件系统允许比8.3 FAT文件系统限定更长的文件名。编译器不能够简单地把更长的头文件名截短为8.3格式,因为这种更长的头文件名的开始八个字符可能不是唯一的。只要编译器遇到long_filename字符串,就用short_filename替换,并且代替查找short_filename头文件。这个编译指示必须出现在相应的#include指令之前,
例如:/
/这两个文件的开头八个字符不是唯一的
#pragma include_alias("AppleSystemHeaderQuickdraw.h","quickdra.h")
#pragma include_alias("AppleSystemHeaderFruit.h","fruit.h")
#pragma include_alias( "GraphicsMenu.h", "gramenu.h")
#include "AppleSystemHeaderQuickdraw.h"
#include "AppleSystemHeaderFruit.h"
#include "GraphicsMenu.h"
无论是拼写,还是双引号或尖括号的用法,被搜索的别名都必须符合规格。include_alias编译指示在该文件名中处理简单的字符串匹配,而在其它的文件名中是无效的。例如,给出如下指令:
#pragma include_alias("mymath.h","math.h")
#include "./mymath.h"
#include "sys/mymath.h"
没有别名使用(替换)被执行,因为头文件字符串并不匹配。用作/Yu、/Yc和/YX编译器选项参量的头文件名,或hdrstop编译指示的头文件名也不能被替换。例如,若你的源文件包含下列指令:
#include
相应的编译器选项应该是:
/YcAppleSystemHeaderStop.h
你可以用include_alias编译指示把任何头文件名映射为另一个。例如:
#pragma include_alias("api.h", "c:/version1.0/api.h")
#pragma include_alias(, )
#include "api.h"
#include
不要把双引号内的文件名和尖括号内的文件名相混淆,例如,对于上面给出的两个#pragma include_alias指令,编译器在下面的#include指令中不执行任何替换:
#include
Include "stdio.h"
此外,下面的指令将导致错误:
#pragma include_alias(,"header.h") //错误
注意在错误信息中给出的文件名,或作为预先定义的__FILE__宏的值,是替换执行之后的文件的名称,例如,下面指令后:
#pragma include_alias("VeryLongFileName.H","myfile.h" )
#include "VeryLongFileName.H"
在VERYLONGFILENAME.H中的一个错误将导致如下错误消息:
myfile.h(15) : error c2059 : syntax error
同时注意传递性是不支持的。如下指令中:
#pragma include_alias( "one.h", "two.h" )
#pragma include_alias( "two.h", "three.h")
#include "one.h"编译器搜索的是文件TWO.H而不是THREE.H。
inline_depth
#pragma inline_depth([0...255])
该指令通过控制一系列函数调用能被扩展的次数(从0到255次),来控制内联扩展可发生的次数。这个编译指示控制标记为inline和_ _inline的函数的联编或在/Ob2选项下已经自动联编的函数。
inline_depth编译指示控制一序列函数调用能被扩展的次数,例如,若联编深度为4,且若A调用B,B调用C,三个调用都将内联扩展。但如果最近的内联扩展为2,只有A和B被扩展,C保留为一个函数调用。
为使用这个编译指示,你必须设置/Ob编译器选项为1或2。使用这个编译指示的深度设置在该编译指示指令后的第一个函数处生效。如果你没有在圆括号中指定一个值,inline_depth将设置联编深度为缺省值8。
联编深度在扩展时只减不增。若联编深度为6,且在扩展时,预处理器遇到一个联编深度值为8的inline_depth编译指示,该深度仍保持为6。
联编深度0禁止联编扩展;联编深度255对联编扩展无限制,若使用一个未指定其值的编译指示,则将使用其缺省值。
inline_recursion
#pragma inline_recursion([{on|off}])
该指令控制直接或相互递归函数调用的联编扩展。该指令用于控制标记为inline和_ _inline的函数,或编译器在Ob2选项下自动扩展的函数。这个编译指示的用法需要一个设置为1或2的/Ob编译器选项。inline_recursion的缺省状态是off。这个编译指示只是在其出现之后的第一个函数处起作用,并且不会影响该函数的定义。
inline_recursion编译指示控制递归函数如何被扩展。如果inline_recursion关闭,且若一个联编函数调用其自身(直接或间接),该函数只被扩展一次。若inline_recursion为打开状态,则该函数将被扩展多以下所列的浮点函数没有真正的内在格式。但它们有这样的版本:将参量直接送入浮点芯片,而不是将它们压入程序栈中:
acos cosh pow tanh
asin fmod sinh
当你指定/Oi和/Og编译器选项(或任何包括/Og、/Ox、/O1和/O2的选项)时,以下浮点函数有真正的内在格式:
atan exp log10 sqrt
atan2 log sin tan
cos
你可以使用/Op或/Za编译器选项重迭真正的内在浮点选项的生成。这种情况下,该函数被生成为库例程,该例程直接把参量送入浮点芯片,而不是把它们压入程序栈。
message
#pragma message(messagestring)
该指令不终止编译,直接把一个字符串文字送到标准输出。message编译指示的典型用法是在编译时显示信息消号。以下代码段使用message编译指示在编译时显示一个消息:
#if _M_IX86==500
#pragma
message("Pentium processor build")#endifmessagestring参数可以是可扩展为一个字符串文字的宏,并且你可以以任何组合方式用字符串文字将这些宏合并起来。例如,下列语句显示了被编译的文件名以及该文件最后改动的日期和时间:
#pragma message("Compiling "__FILE__ )
#pragma message("Last modified on " __TIMESTAMP_ _)
once
#pragma once
该指令指定该编译指示驻留的文件将只在一次建立中被编译器包括(打开)一次。该编译指示的一种普通用法如下:
//header.h
#pragma once
//接着是你的C或C++代码
optimize
#pragma optimize( "[optimization-list]",{on|off} )
仅用于专业和企业版本的特征:代码优化只被Visual C++专业版和企业版支持。更多的信息参见Microsoft Visual C++联机编辑。
该指令指定在函数基中执行的优化。optimize编译指示必须出现在一个函数之外,并且在编译指示出现后定义的第一个函数处产生作用。on和off参量可以打开或关闭在Optimization-list中指定的选项。
optimization-list可以是0或在表2.2中给出参数。
表2.2 "优化"编译指示的参数
参量 优化类型
a 假定无别名
g 允许全局优化
p 提高浮点相容性
s或t 指定机器码的短或快序列
w 假定无交叉函数调用的别名
y 生成程序堆栈中的框架指针
这些是采用/O编译器选项的相同字母,例如:
#pragma optimize("atp", on)
用空字符串("")使用optimize编译指示是该指令的一种特殊形式,它可关闭所有的优化或恢复它们的原有(缺省的)设置。
#pragma optimize("",off)
...
#pragma optimize("", on)
pack
#pragma pack([n])
该指令指定结构和联合成员的紧凑对齐。而一个完整的转换单元的结构和联合
的紧凑对齐由/Zp选项设置。紧凑对齐用pace编译指示在数据说明层设置。该编译指示在其出现后的第一个结构或联合说明处生效。该编译指示对定义无效。当你使用#pragma pack(n)时,这里n为1、2、4、8或16。第一个结构成员之后的每个结构成员都被存储在更小的成员类型或n字节界限内。如果你使用无参量的#pragma pack,结构成员被紧凑为以/Zp指定的值。该缺省/Zp紧凑值为/Zp8。
编译器也支持以下增强型语法:
#pragma pack([[{push|pop},][标识符,]][n])
若不同的组件使用pack编译指示指定不同的紧凑对齐,这个语法允许你把程序组件组合为一个单独的转换单元。
带push参量的pack编译指示的每次出现将当前的紧凑对齐存储到一个内部编译器堆栈中。编译指示的参量表从左到右读取。如果你使用push,则当前紧凑值被存储起来;如果你给出一个n的值,该值将成为新的紧凑值。若你指定一个标识符,即你选定一个名称,则该标识符将和这个新的的紧凑值联系起来。
带一个pop参量的pack编译指示的每次出现都会检索内部编译器堆栈顶的值,并且使该值为新的紧凑对齐值。如果你使用pop参量且内部编译器堆栈是空的,则紧凑值为命令行给定的值,并且将产生一个警告信息。若你使用pop且指定一个n的值,该值将成为新的紧凑值。
若你使用pop且指定一个标识符, 所有存储在堆栈中的值将从栈中删除,直到找到一个匹配的标识符,这个与标识符相关的紧凑值也从栈中移出,并且这个仅在标识符入栈之前存在的紧凑值成为新的紧凑值。如果未找到匹配的标识符,将使用命令行设置的紧凑值,并且将产生一个一级警告。缺省紧凑对齐为8。
pack编译指示的新的增强功能让你编写头文件,确保在遇到该头文件的前后的紧凑值是一样的。
/* File name: include1.h*/
#pragma pack(push,enter_include1)
/* 你的包括文件代码... */
#pragma pack(pop, enter_include1)
/* include1.h结束 */
在上面的例子中,当前紧凑值与标识符enter_include1联系起来,并被压入头文件的项中。头文件末尾的pack编译指示删除所有可能出现在头文件中的干预紧凑值,并且删除与enter_include1相关的紧凑值。因此确保该头文件的前后的紧凑值是相同的。
这种新功能也允许你使用代码,例如头文件,它可以使用pack编译指示设置不同于在你的代码中设置的紧凑值的紧凑对齐:
#pragma pack(push,before_include1)
#include "include1.h"
#pragma pack( pop,before_include1)
在上面的例子中,对于出现在include.h中的紧凑值的任何变化,你的代码是受到保护的。
setlocale
#pragma setlocale("locale_string")
该指令在翻译宽字符常量和字符串文字时定义其场所(国家和语言)。由于用于转换多字节字符为宽位字符的算法可能由于场所或编译而不同,该执行文件在不同的场所运行也可能不同。这个编译指示提供了在编译时给出目标场所的方法。这保证了宽字符串以正确的格式进行存储。缺省的locale_ _string(场所字符串)是 “C”。“C”场所将每个该串中的字符映射为一个wchar_t(unsigned short)型的值。
warning
#pragma warning( warning-specifier:warning-number-list
[,warning-specifier:warning-number-list...])
#pragma warning(push[,n])#pragma warning(pop)
该指令允许选择性地改变编译器的警告消息。
warning-specifier可以是如下值之一:
警告指示符 含义
once 只显示一次指定的消息default将缺省的编译器行为应用于指定的消息
1,2,3,4 把给定的警告级应用于指定的警告消息
disable 不发出指定警告消息
error 作为错误报告指定的警告
warning-number-list(警告编号表)可以包含任何警告编号。在相同的编译指示指令中可指定多个选项如下:
#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
对于那些与代码生成有关,且大于4699的警告编号来说,这个warning编译指示仅当放在函数定义外时有效。如果警告编号大于4699或用在函数体内,则忽略该编译指示。下面的例子指出了禁止warning编译指示的正确位置,且随后恢复一个代码生成警告消息的产生。
int a;
#pragma warning( disable : 4705 )
void func()
{
a;
}
#pragma warning( default : 4705 )
warning编译指示也支持以下语法:
#pragma warning( push[,n])
#pragma warning( pop)
这里n代表警告级(1到4)。
编译指示warning(push)存储所有警告的当前警告状态。编译指示warning(push,n)存储所有警告的当前警告状态并设置全局警告级为n。
编译指示warning(pop)将上次压入栈的警告状态弹出,push和pop之间警告状态的任何变化都将被取消。考虑这个例子:
#pragma warning(push)
#pragma warning(disable : 4705)
#pragma warning(disable : 4706)
#pragma warning(disable : 4707)
// 某些代码
#pragma warning(pop)
在这段代码的未尾,pop恢复所有警告状态(包括4705、4706和4707)为它在代码起始处的警告状态。
当你编写头文件时,可以用push和pop以确保对于用户造成的警告状态的变化,不会影响头部的正确编译。通常在头部的起始处使用push,在末尾处使用pop。例如, 有一个在警告级4未彻底编译的头部。以下代码将警告级改为3,然后在头部的未尾恢复原来的警告级:
#pragma warning(push,3)
//说明/定义
#pragma warning(pop)