Sun Studio 12:C 用户指南

2.8 Pragma

以下形式的预处理行:


#pragma pp-tokens

指定实现定义的操作。

编译系统可识别以下 #pragma。编译器忽略未识别的 pragma。如果使用 -v 选项,将针对无法识别的 pragma 发出警告。

2.8.1 align

#pragma align integer (variable[, variable] )

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


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

2.8.2 c99

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

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

-xc99 选项的值会影响该 pragma。如果 -xc99=all,则该 pragma 设置为 #pragma c99("implicit");如果 -xc99=none,则该 pragma 设置为 #pragma c99("no%implicit")

缺省情况下,该 pragma 设置为 c99=("implicit")

2.8.3 does_not_read_global_data

#pragma does_not_read_global_data (funcname [, funcname])

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

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

2.8.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.8.5 does_not_write_global_data

#pragma does_not_write_global_data (funcname [, funcname])

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

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

2.8.6 error_messages

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

错误消息 pragma 提供源程序内部对 C 编译器和 lint 发出的消息的控制。对于 C 编译器,pragma 只对警告消息有效。C 编译器的 -w 选项通过禁止显示所有警告消息来覆盖该 pragma。

2.8.7 fini

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

使实现在调用 main() 例程之后调用函数 f1fn(完成函数)。此类函数的类型应为 void,并且不接受任何参数,当程序正常终止或所含共享对象从内存中删除时会调用这些函数。和“初始化函数”一样,完成函数按链接编辑器的处理顺序执行。

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

2.8.8 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.8.9 ident

#pragma ident string

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

2.8.10 init

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

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

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

2.8.11 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-xcrossfile

2.8.12 int_to_unsigned

#pragma int_to_unsigned (funcname )

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

2.8.13 MP serial_loop

(SPARC) #pragma MP serial_loop


注 –

Sun 特定的 MP pragma 已过时,并且不再受支持。但是,编译器改为支持 OpenMP 2.5 标准指定的 API。有关标准的指令的迁移信息,请参见《OpenMP API 用户指南》。


有关详细信息,请参阅3.8.3.1 串行 Pragma

2.8.14 MP serial_loop_nested

(SPARC) #pragma MP serial_loop_nested


注 –

Sun 特定的 MP pragma 已过时,并且不再受支持。但是,编译器改为支持 OpenMP 2.5 标准指定的 API。有关标准的指令的迁移信息,请参见《Sun Studio 12: OpenMP API User’s Guide》


有关详细信息,请参阅3.8.3.1 串行 Pragma

2.8.15 MP taskloop

(SPARC) #pragma MP taskloop


注 –

Sun 特定的 MP pragma 已过时,并且不再受支持。但是,编译器改为支持 OpenMP 2.5 标准指定的 API。有关标准的指令的迁移信息,请参见《OpenMP API 用户指南》。


有关详细信息,请参阅3.8.3.2 并行 Pragma

2.8.16 nomemorydepend

(SPARC) #pragma nomemorydepend

该 pragma 指定,对于某个循环的任何迭代,不存在内存依赖性。也就是说,在某个循环的任何迭代内部,不存在对相同内存的引用。该 pragma 将允许编译器(流水线化程序)在某个循环的单次迭代内更有效地调度指令。如果某个循环的任何迭代内部存在任何内存依赖性,则程序的执行结果未定义。编译器在优化级别 3 或更高级别上使用此信息。

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

2.8.17 no_side_effect

(SPARC) #pragma no_side_effect(funcname[, funcname…])

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

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

2.8.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.8.19 pack

#pragma pack(n)

使用 #pragma pack(n) 将影响结构或联合的成员封装。缺省情况下,结构或联合的成员按其自然边界对齐;一个字符型 (char) 数据占一个字节,一个短整型 (short) 数据占两个字节,一个整型 (integer) 数据占四个字节,等等。如果存在 n,它必须为 2 的幂,并且为任何结构或联合成员指定最严格的自然对齐。不接受零。

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

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

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

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


注 –

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


2.8.20 pipeloop

(SPARC) #pragma pipeloop(n )

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

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

2.8.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.8.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.8.23 returns_new_memory

#pragma returns_new_memory (funcname[, funcname])

该 pragma 断言指定函数的返回值在调用点上不使用任何内存作为别名。实际上,该调用返回一个新存储单元。该信息使优化器更好地跟踪指针值并澄清存储单元。这将导致循环的调度、流水线化和并行化的改进。然而,如果断言为假,则程序的行为未定义。

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


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

2.8.24 unknown_control_flow

#pragma unknown_control_flow (funcname[, funcname])

为了描述改变调用程序的流程图的过程, C 编译器提供了 #pragma unknown_control_flow 指令。通常,该指令带有 setjmp() 等函数的声明。在 Sun 系统上,include 文件 <setjmp.h> 包含以下内容:


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

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

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

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

2.8.25 unroll

(SPARC) #pragma unroll (unroll_factor )

对于参数 unroll_factor,该 pragma 接受正整数常量值。当解开因子不为 1 时,该指令作为对编译器的建议,指出指定的循环应由给定的因子解开。如果可能,编译器将使用该解开因子。如果解开因子值为 1,该指令作为一个命令,向编译器指出不解开该循环。编译器在优化级别 3 或更高级别上使用此信息。

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

2.8.26 warn_missing_parameter_info

#pragma [no_]warn_missing_parameter_info

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


exmaple% 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.8.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 的重复定义会导致错误。