跳过导航链接 | |
退出打印视图 | |
Oracle Solaris Studio 12.3:C++ 用户指南 Oracle Solaris Studio 12.3 Information Library (简体中文) |
本节介绍了 C++ 编译器可识别的 pragma 关键字。
#pragma align integer(variable[,variable...])
使用 align 使所列变量与 integer 字节内存对齐,并覆盖缺省设置。请遵循以下限制:
integer 必须是 2 的幂,介于 1 和 128 之间。有效值为 1、2、4、8、16、32、64 和 128。
variable 是一个全局或静态变量。它不能是局部变量或类成员变量。
如果指定的对齐比缺省值小,就使用缺省值。
Pragma 行必须出现在所涉及的变量的声明之前。否则,它将被忽略。
在 pragma 行上涉及但不在下面 pragma 行的代码中声明的任何变量都被忽略。以下示例中的变量是正确声明的。
#pragma align 64 (aninteger, astring, astruct) int aninteger; static char astring[256]; struct S {int a; char *b;} astruct;
#pragma align 在名称空间内部使用时,必须使用改编名称。例如,以下代码中的 #pragma align 语句就是无效的。要更正此问题,应将 #pragma align 语句中的 a、b 和 c 替换为其改编名称。
namespace foo { #pragma align 8 (a, b, c) static char a; static char b; static char c; }
#pragma does_not_read_global_data(funcname[, funcname])
此 pragma 断言,指定的例程不直接或间接读取全局数据,从而在调用此类例程的周围实现更好的代码优化。具体来讲,赋值语句或存储可以围绕这样的调用移动。
指定函数的原型被声明后,该 pragma 才可用。如果全局访问的断言不为真,那么程序的行为就是未定义的。
有关 pragma 如何将重载的函数名视为参数的更加详细的说明,请参见B.1.1 将函数作为 pragma 参数进行重载。
#pragma does_not_return(funcname[, funcname])
此 pragma 向编译器断言,将不会返回对指定例程的调用,从而使编译器可执行与该假定一致的优化。例如,寄存器生命周期在调用点终止,这样可以进行进一步的优化。
如果指定的函数不返回,程序的行为就是未定义的。
指定函数的原型被声明后,该 pragma 才是可用的,如以下示例所示:
extern void exit(int); #pragma does_not_return(exit) extern void __assert(int); #pragma does_not_return(__assert)
有关 pragma 如何将重载的函数名视为参数的更加详细的说明,请参见B.1.1 将函数作为 pragma 参数进行重载。
#pragma does_not_write_global_data(funcname[, funcname])
此 pragma 断言,指定的例程列表不直接或间接写入全局数据,从而在调用此类例程的周围实现更好的代码优化。具体来讲,赋值语句或存储可以围绕这样的调用移动。
指定函数的原型被声明后,该 pragma 才可用。如果全局访问的断言不为真,那么程序的行为就是未定义的。
有关 pragma 如何将重载的函数名视为参数的更加详细的说明,请参见B.1.1 将函数作为 pragma 参数进行重载。
#pragma dumpmacros (value[,value...])
要查看宏在程序中如何工作时,请使用该 pragma。该 pragma 提供了诸如宏定义、取消定义和用法实例的信息,并按宏的处理顺序将输出输出到标准错误 (stderr)。dumpmacros pragma 达到文件结尾或遇到 #pragma end_dumpmacro 之前一直有效。请参见B.2.6 #pragma end_dumpmacros。下表列出了 value 的可能值:
|
注 - 子选项 loc、conds 和 sys 是 defs、undefs 和 use 选项的限定符。使用 loc、conds 和 sys 本身并不会生成任何结果。例如,#pragma dumpmacros(loc,conds,sys) 不起任何作用。
dumpmacros pragma 与命令行选项作用相同,但 pragma 会覆盖命令行选项。请参见A.2.116 -xdumpmacros[= value[,value...]]。
dumpmacros pragma 并不嵌套,因此以下代码行中,处理 #pragma end_dumpmacros 时,将停止打印宏信息:
#pragma dumpmacros(defs, undefs) #pragma dumpmacros(defs, undefs) ... #pragma end_dumpmacros
dumpmacros pragma 的作用是累积的。以下代码行
#pragma dumpmacros(defs, undefs) #pragma dumpmacros(loc)
具有和以下行相同的效果:
#pragma dumpmacros(defs, undefs, loc)
如果使用选项 #pragma dumpmacros(use,no%loc),则使用的每个宏的名称仅输出一次。如果使用选项 #pragma dumpmacros(use,loc),则每次使用宏时都输出位置和宏名称。
#pragma end_dumpmacros
此 pragma 标记 dumpmacros pragma 的结尾,并停止输出有关宏的信息。如果没有在 dumpmacros pragma 后面使用 end_dumpmacros pragma,dumpmacros pragma 会在文件结尾一直生成输出。
#pragma error_messages (on|off| default, tag… tag)
错误消息 pragma 提供源程序内部对编译器发出的消息的控制。Pragma 只对警告消息有效。 -w 命令行选项可通过抑制所有警告消息来覆盖此 pragma。
#pragma error_messages (on, tag… tag)
on 选项结束前面的任何 #pragma error_messages 选项(如 off 选项)的作用域,并覆盖 -erroff 选项的效果。
#pragma error_messages (off, tag… tag)
off 选项阻止编译器程序发出以 pragma 中指定的标记开头的指定消息。pragma 对任何指定的错误消息的作用域仍然有效,直到被另一个 #pragma error_messages 覆盖或编译结束。
#pragma error_messages (default, tag… tag)
default 选项结束前面的任何 #pragma error_messages 指令对指定标记的作用域。
#pragma fini (identifier[,identifier...])
可使用 fini 将 identifier 标记为完成函数。此类函数应为 void 类型,不接受任何参数,当程序在程序控制下终止或从内存删除包含的共享对象时调用它们。与初始化函数一样,完成函数按链接编辑器处理的顺序执行。
在源文件中,#pragma fini 中指定的函数在该文件中的静态析构函数后面执行。在 pragma 中使用标识符之前,请先声明这些标识符。
此类函数每出现在 #pragma fini 指令中一次,就会被调用一次。
可将 hdrstop pragma 嵌入源文件的头文件中以标识源文件活前缀的结尾。例如,考虑以下文件:
example% cat a.cc #include "a.h" #include "b.h" #include "c.h" #include <stdio.h> #include "d.h" . . . example% cat b.cc #include "a.h" #include "b.h" #include "c.h"
源文件活前缀以 c.h 结束,因此可在每个文件中的 c.h 后面插入 #pragma hdrstop。
#pragma hdrstop 只能位于用 CC 命令指定的源文件活前缀的结尾处。不要在任何 include 文件中指定 #pragma hdrstop。
请参见A.2.156 -xpch=v和A.2.157 -xpchstop=file 。
#pragma ident string
可使用 ident 将 string 放在可执行文件的 .comment 部分中。
#pragma init(identifier[,identifier...])
可使用 init 将 identifier 标记为初始化函数。此类函数应为 void 类型,不接受任何参数,在开始执行时构造程序的内存映像的情况下调用。执行将共享对象送入内存的操作时(程序启动时,或执行某些动态装入操作时,例如 dlopen()),执行共享对象中的初始化函数。调用到初始化函数的唯一顺序就是链接编辑器静态和动态处理该函数的顺序。
在源文件中,#pragma init 中指定的函数在该文件中的静态析构函数后面执行。在 pragma 中使用标识符之前,请先声明这些标识符。
此类函数每出现在 #pragma init 指令中一次,就会被调用一次。
ivdep pragma 指示编译器忽略在循环中找到的部分或全部对数组引用的循环附带依赖性,以进行优化。这将使编译器能够执行各种循环优化(例如微向量化、分发、软件流水线等),而以其他方式可能无法执行这些优化。当用户知道这些依赖性无关紧要或者实际上永远不会发生时,可以使用该指令。
#pragma ivdep 指令的解释依赖于 —xivdep 选项的值。
#pragma must_have_frame(funcname[,funcname])
该 pragma 要求总是编译指定的一组函数来获得完整的堆栈帧(如 System V ABI 中所定义)。必须在使用该 pragma 列出函数之前,声明该函数的原型。
extern void foo(int); extern void bar(int); #pragma must_have_frame(foo, bar)
只有在声明了指定函数的原型后,才允许使用该 pragma。该 pragma 必须位于函数结尾之前。
void foo(int) { . #pragma must_have_frame(foo) . return; }
#pragma no_side_effect(name[,name...])
可使用 no_side_effect 指示函数不更改任何持久状态。Pragma 声明了命名的函数不具有任何副作用。也就是说,函数将返回仅依赖于传递参数的结果。此外,函数及其调用的子孙函数行为如下所示:
不读取或写入调用时调用程序中可视程序状态的任何部分。
不执行 I/O。
不更改调用时不可视程序状态的任何部分。
编译器执行优化时可以使用该信息。
如果函数具有副作用,执行调用该函数的程序的结果是未定义的。
name 参数指定当前转换单元中函数的名称。Pragma 必须与函数在相同的作用域,并且必须在函数声明之后出现。pragma 必须在函数定义之前。
有关 pragma 如何将重载的函数名视为参数的更加详细的说明,请参见B.1.1 将函数作为 pragma 参数进行重载。
#pragma opt level (funcname[, funcname])
funcname 指定当前转换单元中定义的函数的名称。level 值指定用于所指定函数的优化级别。可以指定优化级别 0、1、2、3、4、5。可以通过将 level 设置为 0 来关闭优化。必须在该 pragma 之前使用原型或空参数列表声明函数。pragma 则必须对要优化的函数进行定义。
pragma 中所列任何函数的优化级别都降为 -xmaxopt 值。-xmaxopt=off 时,忽略 pragma。
有关 pragma 如何将重载的函数名视为参数的更加详细的说明,请参见B.1.1 将函数作为 pragma 参数进行重载。
#pragma pack([n])
可使用 pack 影响对结构成员的封装。
如果使用了该项,n 必须为 0 或 2 的幂。0 以外的值指示编译器针对数据类型使用 n 字节对齐和平台的自然对齐中的较小者。例如,以下指令使在指令后面(以及后续的 pack 指令前面)定义的所有结构成员对齐时依据的字节边界不严于 2 字节边界,即使正常对齐是 4 或 8 字节边界时也是如此。
#pragma pack(2)
n 为 0 或省略该项时,成员对齐还原为自然对齐值。
如果 n 值等于或大于平台上最严格的对齐时,则采用自然对齐。下表显示了每个平台最严格的对齐。
表 B-1 平台上最严格的对齐
|
pack 指令应用于自身与下一个 pack 指令之间的所有结构定义。如果在具有不同包装的不同转换单元中定义了相同的结构,那么程序可能会因某种原因而失败。具体来说,不应该在包括定义预编译库接口的头文件之前使用 pack 指令。建议将 pack 指令放在要封装的结构紧前面的程序代码中,并将 #pragma pack() 放在该结构紧后面。
如果在 SPARC 平台上使用 #pragma pack 封装效果比类型的缺省对齐紧密,必须为应用程序的编译和链接指定 -misalign 选项。下表显示了整型数据类型的存储大小和缺省对齐。
表 B-2 存储大小和缺省对齐字节数
|
#pragms rarely_called(funcname[, funcname])
此 pragma 向编译器发出提示以说明很少调用指定的函数,从而使编译器可以对此类例程的调用点执行分析反馈式优化,而不需要分析收集阶段的开销。因为该 pragma 只是建议,所以编译器不执行基于该 pragma 的任何优化。
只有在声明指定函数的原型之后,才能使用 #pragma rarely_called 预处理程序指令。以下是 #pragma rarely_called 示例:
extern void error (char *message); #pragma rarely_called(error)
有关 pragma 如何将重载的函数名视为参数的更加详细的说明,请参见B.1.1 将函数作为 pragma 参数进行重载。
#pragma returns_new_memory(name[,name...])
此 pragma 断言,每个指定的函数都返回新分配内存的地址,以及指针没有与任何其他指针相关的别名。使用该信息,优化器可以更好地跟踪指针值,厘清内存分配,从而改善调度和流水作业。
如果该断言为假,那么执行调用该函数的程序的结果是未定义的。
name 参数指定当前转换单元中函数的名称。Pragma 必须与函数在相同的作用域,并且必须在函数声明之后出现。pragma 必须在函数定义之前。
有关 pragma 如何将重载的函数名视为参数的更加详细的说明,请参见B.1.1 将函数作为 pragma 参数进行重载。
#pragma unknown_control_flow(name[,name...])
可使用 unknown_control_flow 指定一组违反过程调用的常规控制流属性的例程。例如,可通过任意的任何其他例程调用来访问 setjmp() 调用后面的语句。该语句通过调用 longjmp() 来访问。
因为这种例程使标准流程图分析无效,调用它们的例程不能安全地优化,所以要禁用优化器来编译这些例程。
如果函数名称被重载,那么会选择最近声明的函数。
#pragma weak name1 [= name2]
可使用 weak 定义弱全局符号。该 pragma 主要在源文件中用于生成库。链接程序在不能解决弱符号时不会发出警告。
weak pragma 可以按以下两种形式之一来指定符号:
字符串形式。字符串必须是 C++ 变量或函数的改编名称。无效改编名称引用的行为是不可预测的。编译器可能不会针对无效的改编名称引用生成错误。无论是否生成错误,使用了无效改编名称时编译器的行为都是不可预测的。
标识符形式。标识符必须是之前在编译单元中声明的 C++ 函数的明确标识符。标识符形式不能用于变量。前端 (ccfe) 遇到无效的标识符引用时会生成错误消息。
采用 #pragma weak name 形式时,指令使 name 成为弱符号。链接程序将不会指示是否未找到 name 的符号定义。它也不会在出现符号的多个弱定义时发出警告。链接程序仅执行第一个遇到的定义。
如果另一个编译单元有函数或变量的强定义,那么 name 将链接到它。如果没有 name 的强定义,那么链接程序符号的值为 0。
以下指令将 ping 定义为弱符号。链接程序找不到名为 ping 的符号的定义时,不会生成错误消息。
#pragma weak ping
采用 #pragma weak name1 = name2 形式时,符号 name1 成为对 name2 的弱引用。如果没有在其他地方定义 name1,那么 name1 的值为 name2。如果在其他地方定义了 name1,那么链接程序使用该定义并忽略对 name2 的弱引用。以下指令指示链接程序解析对 bar(如果已在程序中某处定义)的任何引用,以及解析对 foo 的引用。
#pragma weak bar = foo
采用标识符形式时,必须在当前编译单元中声明和定义 name2。例如:
extern void bar(int) {...} extern void _bar(int); #pragma weak _bar=bar
使用字符串形式时,符号不需要预先声明。如果以下示例中的 _bar 和 bar 都是 extern "C",则不需要声明函数。但 bar 必须在同一对象中定义。
extern "C" void bar(int) {...} #pragma weak "_bar" = "bar"
使用标识符形式时,在 pragma 位置的作用域中必须只有一个具有指定名称的函数。尝试将标识符形式 #pragma weak 用于重载函数会出现错误。例如:
int bar(int); float bar(float); #pragma weak bar // error, ambiguous function name
要避免错误,请使用字符串形式,如以下示例所示。
int bar(int); float bar(float); #pragma weak "__1cDbar6Fi_i_" // make float bar(int) weak
有关更多信息,请参见 Oracle Solaris《链接程序和库指南》。