Oracle® Developer Studio 12.5:C 用户指南

退出打印视图

更新时间: 2016 年 7 月
 
 

2.12 Pragma

通过预处理以下形式的行来指定实现定义的操作。

#pragma pp-tokens

编译系统可识别以下 #pragma。编译器忽略未识别的 pragma。如果使用了 –v 选项,将针对无法识别的 pragma 生成一条警告。

2.12.1 align

#pragma align integer (variable[, variable])

该 pragma 会使用所有提及的变量内存与整数字节对齐,从而覆盖缺省值。请遵循以下限制:

  • integer 值必须是介于 1 和 128 之间的 2 的幂。有效值包括 1、2、4、8、16、32、64 和 128。

  • variable 是一个全局或静态变量。

  • 如果指定的对齐比缺省值小,就使用缺省值。

  • pragma 行必须在它提到的变量的声明前面出现。否则,它将被忽略。

  • 提到但未在 pragma 行后面的文本中声明的任何变量将被忽略。例如:

    #pragma align 64 (aninteger, astring, astruct)
    int aninteger;
    static char astring[256];
    struct astruct{int a; char *b;};

2.12.2 c99

#pragma c99(“implicit” | “no%implicit”)

该 pragma 控制隐式函数声明的诊断。如果将 c99 pragma 值设置为 “implicit”(请注意使用了引号),则编译器在找到隐式函数声明时将生成一条警告。如果将 c99 pragma 值设置为 “no%implicit”(请注意使用了引号),则编译器将无提示地接受隐式函数声明,直到该 pragma 值重置。

-std 选项的值会影响此 pragma 的缺省状态。对于 -std=c11-std=c99,缺省状态为 #pragma c99(“implicit”)。对于 -std=c89,缺省状态为 #pragma c99(“no%implicit”)

2.12.3 does_not_read_global_data

#pragma does_not_read_global_data (funcname [, funcname])

该 pragma 断言指定列表中的例程不直接或间接读取全局数据。通过此行为可更好地围绕此类例程的调用来优化代码。具体来讲,赋值语句或存储可以围绕这样的调用移动。

必须在该 pragma 之前使用原型或空参数列表声明指定的函数。如果全局访问的断言不为真,那么程序的行为就是未定义的。

2.12.4 does_not_return

#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)

2.12.5 does_not_write_global_data

#pragma does_not_write_global_data (funcname [, funcname])

该 pragma 断言指定列表的例程不直接或间接写全局数据。通过此行为可更好地围绕此类例程的调用来优化代码。具体来讲,赋值语句或存储可以围绕这样的调用移动。

必须在该 pragma 之前使用原型或空参数列表声明指定的函数。如果全局访问的断言不为真,那么程序的行为就是未定义的。

2.12.6 dumpmacros

#pragma dumpmacros(value[,value...])

要查看宏在程序中如何工作时,请使用该 pragma。该 pragma 提供了诸如宏定义、取消定义和用法实例的信息,并按宏的处理顺序将输出打印到标准错误 (stderr)。dumpmacros pragma 达到文件结尾或遇到 #pragma end_dumpmacros 之前一直有效。请参见end_dumpmacros。下表列出了 value 的可能值:

含义
defs
打印所有宏定义
undefs
打印所有取消定义的宏
use
打印关于使用的宏的信息
loc
另外打印 defsundefsuse 的位置(路径名和行号)。
conds
打印在条件指令中使用的宏的信息
sys
打印系统头文件中所有宏的定义、取消定义和使用的信息

注 -  子选项 loccondssysdefsundefsuse 选项的限定符。只使用 loccondssys 本身没有任何作用。例如,#pragma dumpmacros(loc,conds,sys) 不起任何作用。

dumpmacros pragma 与命令行选项作用相同,但 pragma 会覆盖命令行选项。请参见-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),则每次使用宏时都打印位置和宏名称。

2.12.7 end_dumpmacros

#pragma end_dumpmacros

此 pragma 标记 dumpmacros pragma 的结尾,并停止打印有关宏的信息。 如果没有在 dumpmacros pragma 后面使用 end_dumpmacros pragma,dumpmacros pragma 会在文件结尾一直生成输出。

2.12.8 error_messages

#pragma error_messages (on|off|default, tag… tag)

error_messages pragma 提供源程序内部对 C 编译器和 lint 发出的消息的控制。对于 C 编译器,pragma 只对警告消息有效。

  • #pragma error_messages (on, tag… tag)

    on 选项结束前面的任何 #pragma error_messages 选项(如 off 选项)的作用域,并覆盖 –erroff 选项的效果。

  • #pragma error_messages (off, tag… tag)

    off 选项阻止 C 编译器或 lint 程序发出以 pragma 中指定的标记开头的指定消息。pragma 对任何指定的错误消息的作用域仍然有效,直到被另一个 error_messages pragma 覆盖或编译结束。

  • #pragma error_messages (default, tag… tag)

    default 选项结束前面的任何 #pragma error_messages 指令对指定标记的作用域。

  • #pragma error_messages will not suppress messages issued by lint pass 2.

    有关 lint 遍数的更多信息,请参见使用 lint

2.12.9 fini

#pragma fini (f1[, f2…,fn]

使实现在调用 main() 例程之后调用函数 f1fn(完成函数)。此类函数需要类型为 void 并且不接受参数。此类函数当程序在程序控制下终止或从内存中删除包含的共享对象时调用。和初始化函数一样,完成函数按链接编辑器的处理顺序执行。

如果完成函数影响全局程序的状态,则应当小心操作。例如,除非接口明确声明您使用系统库完成函数时会发生什么情况,否则您应捕获和恢复所有全局状态信息,如系统库完成函数可能更改的 errno 的值。

此类函数每出现在 #pragma fini 指令中一次,就会被调用一次。

2.12.10 hdrstop

#pragma hdrstop

hdrstop pragma 必须放在最后一个头文件之后,以标识要共享相同预编译头文件的每个源文件中活前缀的结束。例如,考虑以下文件:

example% cat a.c
#include "a.h"
#include "b.h"
#include "c.h"
#include <stdio.h>
#include "d.h"
.
.
.
example% cat b.h
#include "a.h"
#include "b.h"
#include "c.h"

源文件活前缀以 c.h 结束,因此可在每个文件中的 c.h 后面插入 #pragma hdrstop

#pragma hdrstop 必须只在使用 cc 命令指定的源文件的活前缀的末尾出现。不要在任何 include 文件中指定 #pragma hdrstop

2.12.11 ident

#pragma ident string

string 放在可执行文件的 .comment 部分。

2.12.12 init

#pragma init (f1[, f2…,fn])

使实现在调用 main() 之前调用函数 f1fn(初始化函数)。此类函数需要类型为 void 并且不接受参数。当程序在开始执行后构造程序的内存映像时,将调用此类函数。执行将共享对象送入内存的操作时(程序启动时,或执行某些动态装入操作时,例如 dlopen()),执行共享对象中的初始化函数。调用初始化函数的唯一顺序是链接编辑器处理它们的顺序,静态和动态均可。

如果初始化函数影响全局程序的状态,则应额外小心。例如,除非接口明确声明您使用系统库初始化函数时会发生什么情况,否则您应捕获和恢复所有全局状态信息,如系统库初始化函数可能更改的 errno 的值。

此类函数每出现在 #pragma init 指令中一次,就会被调用一次。

2.12.13 inline

#pragma [no_]inline (funcname[, funcname])

该 pragma 对 pragma 的参数中列出的例程名称的内联进行控制。该 pragma 的作用域针对整个文件。该 pragma 只允许全局内联控制,不允许特定于调用点的控制。

#pragma inline 会提示编译器内联当前文件中与 pragma 中列出的例程列表匹配的调用。在某些情况下,此建议可能被忽略。例如,当函数的主体在另一个模块并且未使用交叉文件选项时,忽略该建议。

#pragma no_inline 会提示编译器不内联当前文件中与 pragma 中列出的例程列表匹配的调用。

只有在使用原型或空参数列表声明函数之后,才允许使用 #pragma inline#pragma no_inline,如下例所示。

static void foo(int);
static int bar(int, char *);
#pragma inline(foo, bar)

有关更多信息,请参见编译器选项 -xldscope-xinline-xO-xipo 的说明。

2.12.14 int_to_unsigned

#pragma int_to_unsigned (funcname)

对于返回某个 unsigned 类型的函数,在 –Xt–Xs 模式下,将函数返回值的类型更改为 int

2.12.15 must_have_frame

#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;
  }

2.12.16 nomemorydepend

#pragma nomemorydepend

(SPARC) 该 pragma 指定,在某个循环的任何迭代内,不存在由于引用同一内存地址导致的内存依赖性。该 pragma 将使编译器可以在某个循环的单次迭代内更有效地调度指令。如果某个循环的任何迭代内部存在任何内存依赖性,则程序的执行结果未定义。编译器在优化级别 3 或更高级别上使用此信息。

此 pragma 的作用域从它自身开始,在以下任何一种情况最先出现时结束:下一块的开始部分、当前块内部的下一个 for 循环、当前块的结尾。该 pragma 应用于 pragma 作用域结束前的下一个 for 循环。

2.12.17 no_side_effect

#pragma no_side_effect(funcname[, funcname…])

funcname 指定当前转换单元内部某个函数的名称。必须在该 pragma 之前使用原型或空参数列表声明的函数。必须在函数的定义之前指定 pragma。对于命名的函数 funcname,该 pragma 声明函数无任何副作用,并返回仅依赖于所传递参数的结果值。另外,funcname 和任何已调用的子函数具有如下行为:

  • 不读取或写入调用时调用程序中可视程序状态的任何部分。

  • 不执行 I/O。

  • 不更改调用时不可视程序状态的任何部分。

使用函数进行优化时,编译器使用此信息。如果函数具有副作用,执行调用该函数的程序的结果是未定义的。编译器在优化级别 3 或更高级别上使用此信息。

2.12.18 opt

#pragma opt level (funcname[, funcname])

funcname 指定当前转换单元内部定义的某个函数的名称。level 值指定用于所指定函数的优化级别。可以指定优化级别 0、1、2、3、4 或 5。可以通过将 level 设置为 0 来禁用优化。必须在该 pragma 之前使用原型或空参数列表声明函数。pragma 必须优先于要优化的函数定义。

pragma 中所列任何函数的优化级别都降为 -xmaxopt 值。–xmaxopt=off 时,将忽略该 pragma。

2.12.19 pack

#pragma pack(n)

使用 #pragma pack(n) 将影响结构或联合的成员封装。缺省情况下,结构或联合的成员在其自然边界对齐;对于 char 类型为一个字节,对于 short 类型为两个字节,对于 integer 类型为四个字节,依此类推。如果存在 n,则它必须是 2 的幂,为任何结构或联合成员指定最严格的自然对齐。不接受零。

#pragma pack(n) 指令应用于它后面的所有结构或联合定义,直到出现下一个 pack 指令。如果在具有不同包装的不同转换单元中定义了相同的结构或联合,那么程序会因某种原因而失败。特别是,不应在包含定义了预编译库的接口的头文件之前使用 #pragma pack(n)。#pragma pack(n) 的建议用法是,将它放在程序代码中紧挨在要封装的任何结构或联合的前面。在封装的结构后面紧跟 #pragma pack( )。

您可以使用 #pragma pack(n) 为结构或联合成员指定对齐边界。例如,#pragma pack(2) 会使 int、long、long long、float、double、long double 和指针与双字节边界对齐,而不是与其自然边界对齐。

如果 n 等于或大于您使用的平台上最严格的对齐(在 x86 上使用 -m32 时为 4,在 SPARC 上使用 -m32 时为 8,但使用 -m64 时为 16),则指令具有自然对齐的效果。同样,如果省略 n,成员对齐将恢复为自然对齐边界。

请注意,使用 #pragma pack 时,封装的结构或联合本身的对齐方式与其更严格对齐的成员相同。因此,该 structunion 的任何声明将使用 pack 对齐。例如,只包含 char 数据的 struct 无对齐限制,而包含 double 数据的 struct 将按 8 字节边界对齐。


注 -  如果您使用 #pragma pack 将结构或联合成员与其自然边界以外的边界对齐,则访问这些字段通常会导致 SPARC 出现总线错误。要避免发生此错误,请确保同时还指定了 -xmemalign 选项。有关编译此类程序的最佳方法,请参见-xmemalign=ab
#pragma pack(push[,n])

使用 #pragma pack(push[,n]) 可将当前的对齐设置推送到内部堆栈上,并可以选择将新对齐设置为给定值 n

#pragma pack(pop)

使用 #pragma pack(pop) 可将对齐设置为通过之前的下述操作保存到内部堆栈的最后一个值:对该堆栈条目执行的推送和删除以及弹出操作。


注 -  #pragma pack(n) 不影响内部堆栈。

2.12.20 pipeloop

#pragma pipeloop(n)

对于参数 n,该 pragma 接受正整型常量值或 0。该 pragma 指定,循环可流水线化,并且循环携带的依赖性的最小依赖距离为 n。如果该距离为 0,则循环实际上是 Fortran 风格的 doall 循环,并且应在目标处理程序上流水线化。如果该距离大于 0,则编译器(流水线化程序)将只尝试流水线化 n 次连续迭代。编译器在优化级别 3 或更高级别上使用此信息。

此 pragma 的作用域从它自身开始,在以下任何一种情况最先出现时结束:下一块的开始部分、当前块内部的下一个 for 循环、当前块的结尾。该 pragma 应用于 pragma 作用域结束前的下一个 for 循环。

2.12.21 rarely_called

#pragma rarely_called(funcname[, funcname])

该 pragma 提示编译器,指定的函数很少被调用。然后,编译器可以在此类例程的调用点执行分析反馈样式的优化,而没有分析收集阶段的开销。因为该 pragma 只是建议,所以编译器可以选择不执行基于该 pragma 的任何优化。

必须在该 pragma 之前使用原型或空参数列表声明指定的函数。以下是 #pragma rarely_called 的一个示例:

extern void error (char *message);
#pragma rarely_called(error)

2.12.22 redefine_extname

#pragma redefine_extname old_extname new_extname

该 pragma 导致对象代码中名称 old_extname 的各个外部定义具体值被 new_extname 替换。结果,链接程序在链接时只看到名称 new_extname。如果在第一次使用 old_extname 作为函数定义、初始化函数或表达式之后遇到 #pragma redefine_extname,则该作用未定义。(在 – Xs 模式下不支持该 pragma。)

如果 #pragma redefine_extname 可用,编译器会提供预定义宏 __PRAGMA_REDEFINE_EXTNAME 的定义,可使用其编写在有无 #pragma redefine_extname 的条件下均可运行的可移植代码。

#pragma redefine_extname 提供了一种在函数名称无法更改时重新定义函数接口的有效方法。例如,如果某个库中必须保留初始函数定义,为了与现有程序兼容,创建同一函数的新定义以供新程序使用,可以按新名称将该新函数定义添加到库中。随后,声明函数的头文件使用 #pragma redefine_extname,以便对函数的所有使用均与该函数的新定义链接。

#if    defined(__STDC__)

#ifdef __PRAGMA_REDEFINE_EXTNAME
extern int myroutine(const long *, int *);
#pragma redefine_extname myroutine __fixed_myroutine
#else /* __PRAGMA_REDEFINE_EXTNAME */

static int
myroutine(const long * arg1, int * arg2)
{
    extern int __myroutine(const long *, int*);
    return (__myroutine(arg1, arg2));
}
#endif /* __PRAGMA_REDEFINE_EXTNAME */

#else /* __STDC__ */

#ifdef __PRAGMA_REDEFINE_EXTNAME
extern int myroutine();
#pragma redefine_extname myroutine __fixed_myroutine
#else /* __PRAGMA_REDEFINE_EXTNAME */

static int
myroutine(arg1, arg2)
    long *arg1;
    int *arg2;
{
    extern int __fixed_myroutine();
    return (__fixed_myroutine(arg1, arg2));
}
#endif /* __PRAGMA_REDEFINE_EXTNAME */

#endif /* __STDC__ */

2.12.23 returns_new_memory

#pragma returns_new_memory (funcname[, funcname])

该 pragma 断言指定函数的返回值在调用点上不使用任何内存作为别名。实际上,该调用返回一个新存储单元。通过此信息,优化器可以更好地跟踪指针值和说明内存位置,从而改善循环的调度、流水线作业和并行化。然而,如果断言为假,则程序的行为未定义。

只有在使用原型或空参数列表声明指定的函数之后才允许使用该 pragma,如下例所示。

void *malloc(unsigned);
#pragma returns_new_memory(malloc)

2.12.24 unknown_control_flow

#pragma unknown_control_flow (funcname[, funcname])

要描述改变函数调用程序流程图的过程,请使用 #pragma unknown_control_flow 指令。通常,该指令带有 setjmp() 等函数的声明。在 Oracle Solaris 系统上,include 文件 <setjmp.h> 包含以下代码:

extern int setjmp();
#pragma unknown_control_flow(setjmp)

同样,必须声明具有 setjmp() 类似属性的其他函数。

原则上,识别该属性的优化器可在控制流程图中插入相应的界限,从而在调用 setjmp() 的函数中安全地处理函数调用,同时保持优化流程图的未受影响部分的代码的能力。

必须在该 pragma 之前使用原型或空参数列表声明指定的函数。

2.12.25 unroll

#pragma unroll (unroll_factor)

对于参数 unroll_factor,此 pragma 接受正整型常量值。如果将 unroll_factor 设置为 1 之外的值,这将向编译器表明,指定的循环应尽可能由给定的因子解开。如果 unroll_factor 为 1,则此指令将命令编译器不要解开循环。编译器在优化级别 3 或更高级别上使用此信息。

此 pragma 的作用域从它自身开始,在以下任何一种情况最先出现时结束:下一块的开始部分、当前块内部的下一个 for 循环、当前块的结尾。该 pragma 应用于 pragma 作用域结束前的下一个 for 循环。

2.12.26 warn_missing_parameter_info

#pragma [no_]warn_missing_parameter_info

如果指定 #pragma warn_missing_parameter_info,编译器将针对函数声明不包含任何参数类型信息的函数调用发出一条警告。请看以下示例:

example% cat -n t.c
     1    #pragma warn_missing_parameter_info
     2    
     3    int foo();
     4    
     5    int bar () {
     6    
     7       int i;
     8    
     9       i = foo(i);
    10    
    11       return i;
    12    }
% cc t.c -c -errtags
"t.c", line 9: warning: function foo has no prototype (E_NO_MISSED_PARAMS_ALLOWED)
example%

#pragma no_warn_missing_parameter_info 将使任何以前的 #pragma warn_missing_parameter_info 无效。

缺省情况下,#pragma no_warn_missing_parameter_info 是有效的。

2.12.27 weak

#pragma weak symbol1 [= symbol2]

此 pragma 定义弱全局符号。它主要在构建库时使用。如果链接程序无法解析弱符号,它并不生成错误消息。

#pragma weak symbol

symbol 定义为弱符号。如果链接程序找不到 symbol 的定义,它不会生成错误消息。

#pragma weak symbol1 = symbol2

symbol1 定义为弱符号,它是符号 symbol2 的别名。只能在已定义 symbol2(可以在源文件中定义,也可以在其包含的某个头文件中定义)的同一转换单元中使用这种形式的 pragma。否则,将导致编译错误。

如果程序调用但未定义 symbol1,并且 symbol1 在所链接的库中是弱符号,则链接程序使用该库中的定义。但是,如果程序定义自己的 symbol1 版本,则使用该程序的定义,而不使用库中 symbol1 的弱全局定义。如果程序直接调用 symbol2,则将使用库中的定义。重复定义 symbol2 会导致错误。