#pragma align integer(variable [,variable...]) |
可使用 align使所列变量与 integer 字节内存对齐,并覆盖缺省值。请遵循以下限制:
integer 必须是介于 1 和 128 之间的 2 的幂,有效值包括 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 可以是下列参数:
值 |
含义 |
---|---|
defs |
打印所有宏定义 |
undefs |
打印所有取消定义的宏 |
use |
打印关于使用的宏的信息 |
loc |
另外打印 defs、undefs 和 use 的位置(路径名和行号) |
conds |
打印在条件指令中使用的宏的信息 |
sys |
打印系统头文件中所有宏的定义、取消定义和使用的信息 |
子选项 loc、conds 和 sys 是 defs、undefs 和 use 选项的限定符。使用 loc、conds 和 sys 本身并不会生成任何结果。例如,#pragma dumpmacros=loc,conds,sys 不会生成什么结果。
dumpmacros pragma 与命令行选项作用相同,但 pragma 会覆盖命令行选项。请参见A.2.123 -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 fini (identifier[,identifier...]) |
可使用 fini 将 identifier 标记为完成函数。此类函数应为 void 类型,不接受任何参数,当程序在程序控制下终止或从内存删除包含的共享对象时调用它们。与初始化函数一样,完成函数按链接编辑器处理的顺序执行。
在源文件中,#pragma fini 中指定的函数在该文件中的静态析构函数后面执行。在 pragma 中使用标识符之前,请先声明这些标识符。
可将 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.162 -xpch=v和A.2.163 -xpchstop=file。
#pragma ident string |
可使用 ident 将 string 放在可执行文件的 .comment 部分中。
#pragma init(identifier[,identifier...]) |
可使用 init 将 identifier 标记为初始化函数。此类函数应为 void 类型,不接受任何参数,在开始执行时构造程序的内存映像的情况下调用。执行将共享对象送入内存的操作时(程序启动时,或执行某些动态装入操作时,例如 dlopen()),执行共享对象中的初始化函数。调用到初始化函数的唯一顺序就是链接编辑器静态和动态处理该函数的顺序。
在源文件中,#pragma init 中指定的函数在该文件中的静态析构函数后面执行。在 pragma 中使用标识符之前,请先声明这些标识符。
#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 平台上最严格的对齐
平台 |
最严格的对齐 |
---|---|
x86 |
4 |
SPARC 通用、V8、V8a、V8plus、V8plusa、V8plusb |
8 |
SPARC V9、V9a、V9b |
16 |
pack 指令应用于自身与下一个 pack 指令之间的所有结构定义。如果在具有不同包装的不同转换单元中定义了相同的结构,那么程序会因某种原因而失败。具体来说,不应该在包括定义预编译库接口的头文件之前使用 pack 指令。建议将 pack 指令放在要封装的结构紧前面的程序代码中,并将 #pragma pack() 放在该结构紧后面。
如果在 SPARC 平台上使用 #pragma pack 封装效果比类型的缺省对齐紧密,必须为应用程序的编译和链接指定 -misalign 选项。下表显示了整型数据类型的存储大小和缺省对齐。
表 B–2 存储大小和缺省对齐字节数
类型 |
SPARC V8 大小,对齐 |
SPARC V9 大小,对齐 |
x86 大小,对齐 |
---|---|---|---|
bool |
1,1 |
1,1 |
1,1 |
char |
1,1 |
1,1 |
1,1 |
short |
2,2 |
2,2 |
2,2 |
wchar_t |
4,4 |
4,4 |
4,4 |
int |
4,4 |
4,4 |
4,4 |
long |
4,4 |
8,8 |
4,4 |
float |
4,4 |
4,4 |
4,4 |
double |
8,8 |
8,8 |
8,4 |
long double |
16,8 |
16,16 |
12,4 |
指向数据的指针 |
4,4 |
8,8 |
4,4 |
指向函数的指针 |
4,4 |
8,8 |
4,4 |
指向成员数据的指针 |
4,4 |
8,8 |
4,4 |
指向成员函数的指针 |
8,4 |
16,8 |
8,4 |
#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 |
有关更多信息,请参见 Solaris《链接程序和库指南》。