2004 年 5 月 27 日更新 |
Sun[tm] Studio 9:C++ 编译器自述文件 |
目录
A. 简介
本文档包含有关 Sun Studio 9 C++ 5.6 编译器的信息。本文档中,该编译器也称为 C++ 编译器 5.6 版。本文档描述了本发行版本的一些新功能,包括此发行版本作出的软件更正,并列出了已知的问题、限制和不兼容性。本文档中的信息更新和扩展了软件手册中的信息。
产品文档
- Solaris 平台的发行说明:可以通过 Sun Studio 9 网站 http://developers.sun.com/tools/cc/documentation/ss9_docs/release_notes.html 获得此发行说明。发行说明中的信息会更新和扩展所有自述文件中的信息。
- Sun Studio 9 文档:产品手册页、自述文件的 HTML 版本以及手册可以从 /installation_directory/SUNWspro/docs/index.html 进行访问。缺省安装目录为 /opt。您可以从 index.html 页访问下列文档:
- C++ 常见问题
- C++ 用户指南
- C++ 迁移自述文件
- C++ 迁移指南
- 标准 C++ 库类参考
- 标准 C++ 库用户指南
- Tools.h++ 7.1.0 自述文件
- Tools.h++ 用户指南
- Tools.h++ 类库参考
- 间隔运算自述文件
- C++ 区间运算编程参考
- 数学库自述文件
- 运行时库自述文件
- 数值计算指南
- 增量式链接编辑器自述文件
- CC (1) 手册页
- 3C++ 手册页(标准 C++ 库)
- 3CC4 手册页(兼容模式库)
- 集成开发环境 (IDE) 文档:Sun Studio 9 IDE 所有组件的联机帮助可从 IDE 中的 [帮助] 菜单进行访问。
- 开发人员资源门户:有关技术文章、代码样例、文档和知识库,请参见开发人员门户,网址:http://developers.sun.com/prodtech/cc。
要查看本自述的文本格式文件,请输入以下的命令:
CC -xhelp=readme
要查看本自述的 HTML 格式文件,请转到缺省安装目录:
file:/opt/SUNWspro/docs/index.html注意—如果 Sun Studio 9 软件未安装在缺省 /opt 目录中,请询问系统管理员以获得系统中的等价路径。
B. 关于 Sun Studio 9 C++ 编译器 5.6
此发行版本的 C++ 编译器可以运行在以下环境中:Solaris[tm] 操作环境 (SPARC (R); 平台版) 版本 8、版本 9 和版本 10,以及 Solaris 操作环境 (x86 平台版) 版本 8、版本 9 和版本 10。
C++ 编译器 5.6 版本与 5.0 版到 5.5 版本在源代码级和二进制级兼容。也就是说,您可以用 C++ 编译器 5.5 版来编译可以用版本 5.0 到 5.5 进行编译的源代码。另外,您还可以将版本 5.0 到 5.5 生成的目标代码和 C++ 编译器 5.6 生成的目标代码链接到一起。应确保总是使用最新的编译器进行链接,目前的最新版本是 5.6。
C++ 编译器 5.6 版也为采用 4.2 版编写的源代码进行编译提供了 -compat 选项。该 -compat 选项在版本 5.0 中首次引入。
C. 新特性和更改的特性
本节描述了 C++ 编译器的新功能和更改功能。有关其他 Sun Studio 9 组件的信息,参见《新增功能》手册。要访问此手册,请转到 http://docs.sun.com。
通过为 -xarch、-xcode、-xmemalign 和 -xprefetch 选项提供新的缺省设置并通过为 -O 选项提供新的扩展功能,提高了性能。
通过新的 -xprefetch_auto_type 和 -sync_stdio 选项,提高了运行时性能。
通过用 -xpch 自动生成的预编译头文件,提高了编译时性能。
通过 -xrestrict 选项,对 extern INLINE 函数和受限指针识别提供缺省支持。
通过 #pragma opt 指令和 -xmaxopt 选项控制优化级别。
通过 -xustr 选项增强 UTF-16 宽字符支持。
新的 -xarch 缺省值:v8plus
现在,C++ 编译器为其生成代码的缺省体系结构是 v8plus (UltraSPARC)。在将来的版本中将丢弃对 v7 的支持。
新的缺省值几乎可以为当前使用的所有机器提供更高的运行时性能。然而,对于计划在预装 UltraSPARC 计算机上部署的应用程序,缺省情况下将不在这些计算机上执行。使用 -xarch=v8 进行编译,以确保应用程序在这些计算机上执行。
如果您想在 v8 系统上进行部署,则必须在每个编译器命令行以及任何链接时命令中明确指定选项 -xarch=v8。提供的系统库在 v8 体系结构上运行。
如果您想在 v7 系统上进行部署,则必须在每个编译器命令行以及任何链接时命令中明确指定选项 -xarch=v7。提供的系统库使用 v8 指令集。对于 Sun Studio 9 发行版,v7 唯一支持的操作系统是 Solaris 8 发行版。遇到 v8 指令时,Solaris 8 操作系统解释软件中的指令。程序运行,但是性能并不下降。
对于 x86 平台,-xarch 的缺省值为 generic。注:x86 平台上的 -fast 扩展至 -xarch=native。
关于 -xarch 的更多信息,请参见 C++ 手册页 CC(1) 或《C++ 用户指南》。
x86 平台上新的 -xarch、-xtarget 和 -xchip 标记C++ 编译器支持新的 -xarch、-xtarget 和 -xchip 标记。这些新标记设计用于将 Pentium 3 和 Pentium 4 芯片的性能与 Solaris 软件充分结合,以支持 x86 平台上的 sse 和 sse2 指令。新的选项如下:
- -xchip=pentium3 为 Pentium 3 类型的处理器进行了优化。
- -xchip=pentium4 为 Pentium 4 类型的处理器进行了优化。
- -xtarget=pentium3 设置 -xarch=sse、-xchip=pentium3 和 -xcache=16/32/4:256/32/4。
- -xtarget=pentium4 设置 -xarch=sse2、-xchip=pentium4 和 -xcache=8/64/4:256/128/8。
- -xarch=sse 将 SSE 指令集添加到 pentium_pro 指令集中。
- -xarch=sse2 向那些 SSE 允许的指令集添加 SSE2 指令集
特别注意
用 -xarch={sse | sse2} 编译以便在 Solaris x86 SSE/SSE2 Pentium 4 兼容平台上运行的程序必须只在启用 SSE/SSE2 平台上运行。在未启用 SSE/SSE2 的平台上运行这种程序可能会导致段故障或者不发出明确警告信息就产生错误结果。操作系统和编译器的补丁程序可防止 SSE/SSE2 编译的二进制程序在未启用 SSE/SSE2 的平台上执行,这些补丁程序可能会在晚些时候提供。以 Solaris 9 update 6 开头的操作系统版本在 Pentium 4 兼容平台上启用 SSE/SSE2。Solaris OS 的早期版本未启用 SSE/SSE2。
该警告还扩展到利用 .il 联机汇编语言功能程序或利用 SSE/SSE2 指令的 __asm() 汇编程序代码。
如果您在各个独立的步骤中进行编译和链接,则要始终使用编译器并通过 -xarch={sse | sse2} 进行链接,以确保链接正确的启动例程。
遵照下列准则,您可以确定 -xchip、-xtarget 和 -xarch 选项的哪个组合符合您的需要:
是否在运行 Solaris 9 update 5 或更低版本的 Pentium 3 或 Pentium 4 计算机上进行构建,并且是否指定了 -fast、-xarch=native 或 -xtarget=native?
如果是这样,编译器将进行下列扩展:
-xarch 设置为 pentium_pro(而不是您期望的 pentium3 或 pentium4),因为 Solaris 9 update 5 或更低版本的操作系统不支持 SSE 和 SSE2 指令。
注意: 即使使用这些版本的 Solaris 软件,也可以指定 -xarch=sse 或 -xarch=sse2,但必须在运行 Solaris 9 update 6 或更高版本的计算机上运行相应版本提供的可执行文件,因为这些版本的 Solaris 软件支持 SSE 和 SSE2 指令。
- 根据需要,将 -xchip 设置为 pentium3 或 pentium4。
-xcache 设置为 16/32/4:256/32/4(对于 Pentium 3 处理器)或 8/64/4:256/128/8(对于 Pentium 4 处理器)。
是否在运行 Solaris 9 update 6 或更高版本的 Pentium 3 或 Pentium 4 计算机上进行构建,并且是否指定了 -fast、-xarch=native 或 -xtarget=native?
如果是这样,编译器将进行下列扩展:
- -xarch 设置为 sse(对于 Pentium 3)或 sse2(对于 Pentium 4)。
- 根据需要,将 -xchip 设置为 pentium3 或 pentium4。
- 对于 Pentium 3,将 -xcache 设置为 16/32/4:256/32/4;对于 Pentium 4,则将它设置为 8/64/4:256/128/8。
关于 -xarch、-xtarget 和 -xchip 的更多信息,请参见 C++ 手册页 CC(1) 或《C++ 用户指南》。
新的 -O 扩展(SPARC 和 x86)-O 宏现已扩展至 -xO3,而不是 -xO2。
缺省情况下,更改将带来更高的运行时性能。但是,-x03 可能并不适合那些所有变量均被自动认为是 volatile 的程序。可能具有此假设的典型程序是实现其同步基元的设备驱动程序和较旧的多线程应用程序。其解决办法是使用 -xO2 而不是 -O 进行编译。
关于 -O 的更多信息,请参见 C++ 手册页 CC(1) 或《C++ 用户指南》。
新的 -xprefetch 缺省值(SPARC) 现在,-xprefetch 的缺省值是 -xprefetch=auto,explicit。此更改将对本质上为非线性内存访问模式造成不利影响。要禁用更改功能,请指定 -xprefetch=no%auto,no%explicit。
关于 -xprefetch 的更多信息,请参见 C++ 手册页 CC(1) 或《C++ 用户指南》。
新的 -xmemalign 缺省值(SPARC) 对于所有的 v8 体系结构,-xmemalign 的缺省值为 -xmemalign=8i。所有 v9 体系结构的缺省值为 -xmemalign=8s。
关于 -xmemalign 的更多信息,请参见 C++ 手册页 CC(1) 或《C++ 用户指南》。
新的 -xcode 缺省值(SPARC) V9 上的缺省值为 -xcode=abs44。V8 上的缺省值还是 -xcode=abs32。在 x86 平台上不支持 –xcode。
注意—对于 v9,不能在用于共享库的代码中使用缺省的 -xcode=abs44。这种版本的共享库因为重定位错误而失败。必须用 -xcode=abs64 或者选项进行编译,以生成与位置无关的代码,比如 -xcode=pic13 或 -xcode=pic32。
关于 -xcode 的更多信息,请参见 C++ 手册页 CC(1) 或《C++ 用户指南》。
新的 -xchip 和 -xtarget 标记(SPARC) 现在,-xchip 和 -xtarget 选项支持 ultra3i 和 ultra4 作为其值,因此您可以构建为 UltraSPARC IIIi 和 UltraSPARC IV 处理器进行了优化的应用程序。
外部内联函数C++ 标准指出,除非声明为静态,否则内联函数象非内联函数一样具有外部链接。C++ 5.6 首次在缺省情况下为内联函数提供了外部链接。如果必须不使用命令行生成内联函数(例如,如果需要它的地址),则只将一个副本链接到最终程序。以前,需要副本的每个目标文件都有自己带有本地链接的副本。
这种 Extern 内联函数的实现与早期版本的编译器创建的二进制文件兼容,在某种意义上说程序行为如同以前一样符合标准。旧的二进制文件可以有内联函数的多个本地副本,但新的代码将最多只有一个 Extern 内联函数的副本。
使用本发行版本包括的 C 5.6 编译器,这种外部内联函数的实现与 C99 版本的内联函数兼容。即,遵循外部内联函数的 C 和 C++ 规则,可以在 C 和 C++ 文件中定义同样的内联函数,并且该外部函数只有一个副本将出现在最终程序中。
编译器之间存在一种不兼容,因为 C 语言允许非内联函数支持(提供外部定义)内联函数。C++ 语言没有这种概念。将这两种内联方法混合将会导致链接程序错误。考虑下面的示例:
//File a.h #ifdef __cplusplus extern "C" { #endif inline int f() { return 1; } #ifdef __cplusplus } #endif //File b.c #include "a.h" int g() { return f(); }在文件 b.c 中,内联函数 f 被一个函数支持,这个函数没有指明它支持内联函数。
//File c.c int f() { return 1; }如果将 c.c 和 f 的 C++ 使用混合(如下所示),您就会从链接程序那里获得“多个定义”的错误消息。
//File d.cc #include "a.h" int h() { return f(); }解决方法是告诉 C 编译器说,函数 f 支持内联函数。请使用 c.c 的下列实施。
//File c.c #include "a.h" extern inline int f();使用 -xautopar、-xvector 和 -xdepend 进行循环优化对于可以实现并行计算的循环优化,C++ 编译器现在支持以下选项。这些选项必须用于优化级别 -xO3 或更高。
- -xautopar
- -xvector
- -xdepend
有关详细信息,请参见 C++ 手册页 CC(1) 中有关 -xautopar、-xvector 和 -xdepend 的说明。
通过 -xrestrict 限制的指针C++ 不支持 C99 中引入的 restrict 关键字。但 C++ 编译器现在接受 C 编译器选项 -xrestrict。
此选项声明编译过程中的函数对指针类型的函数参数不引用相同的或重叠的对象的影响。此选项在 C++ 中的危险性比在 C 中更大,因为对于在头文件中定义的内联函数,此声明可能不为 True。
有关详细信息,请参见 C++ 手册页 CC(1) 中有关 -xrestrict 的说明。
通过 #pragma opt 和 -xmaxopt 控制优化级别可以将 #pragma opt 指令与命令行选项 -xmaxopt 结合在一起来指定编译器应用于各个函数的优化级别。
例如,如果为了避免诸如消除堆栈帧的代码增强,需要降低特定函数的优化级别时,或为了增大特定函数的优化级别时,这种组合非常有用。
有关详细信息,请参阅 C++ 手册页 CC (1) 中有关 -xmaxopt 的说明。
通过新的 -xprefetch_auto_type 选项改进运行时性能。使用新的 -xprefetch_auto_type 选项能够以与生成直接内存访问预取相同的方式,为选项 -xprefetch_level=[1|2|3] 指示的循环生成间接预取。
诸如 -xalias_level 这样的选项可以改进 -xprefetch_auto_type的优化好处。它们将影响计算间接预取侯选对象的激进度,从而将影响自动间接预取插入的激进度,因为它们有助于生成更准确的内存别名二义性信息。
关于 -xprefetch_auto_type 选项的更多信息,请参见 CC(1) 手册页或《C++ 用户指南》。
通过新的 -sync_stdio 选项提高了运行时性能。运行时性能不好的一个原因可能是 C++ iostreams 和 C stdio 同步。这种同步是 C++ 标准所要求的,编译器在缺省情况下启用这种同步。但是,您可以通过指定 -sync_stdio=no 来禁用这种同步。
关于 -sync_stdio 选项的更多信息,请参见《C++ 用户指南》或 CC(1) 手册页。另请参见 C++ 问答,以获取有关该问题解答的讨论。
通过 -xustr 增强 UTF-16 支持5.5 版本的 C++ 编译器引入了对 UTF-16 字符串文字的支持。本发行版扩展了对 UTF-16 字符文字的支持,其中 UTF-16 字符文字使用的语法 U'x' 与字符串的 U"x" 语法类似。需要相同的 -xustr 选项来支持 UTF-16 字符文字识别。
本发行版本也支持 UTF-16 字符文字和字符串文字中的数字换码,这种数字换码与普通的字符文字和字符串中的数字换码类似。例如:
U"ab\123ef" // 在八进制中表示字符 U'\x456' // 在十六进制中表示字符有关详细信息,请参见 C++ 手册页 CC(1) 中有关 -xustr 的说明。
使用 -xpch 自动生成预编译头文件本发行版本的 C++ 编译器将预编译头文件功能扩展为包括编译器的一项自动功能,能够生成预编译的头文件。您仍可以选择手动生成预编译头文件,但如果您对编译器的新功能感兴趣,请参见 CC(1) 手册页中有关 -xpch 选项的说明来了解更多信息。另请参见 CCadmin(1) 手册页。
D. 软件更正
本节介绍以下软件更正:
- 改正大型十进制整数常量的解释
- 二义性:构造函数调用或者函数指针
- 在 Solaris 8 的 update 2 和补丁软件中修正了 __ctype 未定义错误。
- 在模板中支持静态变量的 -instance=static 和 -instance=semiexplicit
- Extern 内联函数的函数局部静态变量的不同行为
- 不再忽略模板语法错误
改正大型十进制整数常量的解释
C++ 标准指明,没有后缀的十进制整数常量被当作 int 处理(如果值符合 int 的话),否则就被当作 long int 处理。如果值不符合 long int,结果就不确定。
在 32 位模式中,int 和 long 有相同的尺寸和数据范围。C++ 编译器遵循 1990 C 标准规则,将 INT_MAX+1 和 LONG_MAX 之间的值当作无符号的 long 处理。这种处理在某些程序中会生成意外的结果。
1999 C 标准更改有关无后缀十进制整数的规则,这样它们就永远不会被当作无符号类型处理。类型是 int、long 或 long long 中第一个可以代表值的类型。
C++ 5.6 在标准模式中遵循 C99 规则,但在 -compat=4 模式中继续遵循 C90 规则。(在 -compat=4 模式中,编译器的行为类似于 C++ 4.2 编译器。)
如果您希望大的十进制整数被处理成无符号,则方便的解决方法是使用 u 或 U 后缀。同样,可以对其他类型使用其他后缀。例如:
// note:2147483648 == (INT_MAX+1) 2147483648 // (signed) long long 2147483648LL // (signed) long long 2147483648U // same as 2147483648u二义性:构造函数调用或者函数指针
某些 C++ 语句有可能解释成声明或者表达式。C++ 二义性规则为:如果一个语句可以处理成声明,那么它就是声明。
早期版本的编译器会错误解释下面的代码:
struct S { S(); }; struct T { T( const S& ); }; T v( S() ); // ???编程者也许本来打算在最后一行定义变量 v,并且用类型为 S 的临时变量对它进行初始化。早期版本的编译器会这样解释这条语句。
但是在声明环境里,构造符号“S()”也可被提取成声明符(不带标识符),表示“不带参数的函数返回类型值 S”。在这种情况下,该语句会自动转化成函数指针“S(*)()”。这样该语句即可作为函数 v 的声明,该函数有一个函数指针类型的参数,返回值类型为 T。
当前版本的编译器现在可以正确解释该语句,但这未必是编程者所想要的结果。
有两种修改方法使上面的代码没有二义性:
T v1( (S()) ); // v1 是初始化对象 T v2( S(*)() ); // v2 是一个函数第一行另加的那对括号使 v1 不可能是函数声明,因为这样的语法无效,所以它的唯一解释是“利用类型为 S 的临时值进行初始化的类型为 T 的对象”。
同样,构造符号“S(*)()”也不可能是值,所以它的唯一解释是函数声明。
第一行也可以改写为:
T v1 = S();虽然这时语句含义非常清楚,但这种形式的初始化会导致创建一个额外的临时变量,而一般情况下这不会发生。
建议不要编写与下面语句类似的代码,因为它的含义不清楚,不同的编译器可能会出现不同的结果。
T v( S() ); // 不建议在 Solaris 8 的 update 2 和补丁软件中修正了 __ctype 未定义错误
在 Solaris 8 操作系统中有一个错误,如果使用 <stdlib.h> 的 MB_CUR_MAX,C++ 编译器会出现“__ctype 未定义错误”。
Solaris 8 update 2 操作系统已经更正了这个错误。从 Solaris 补丁程序 109607-01(SPARC) 和 109608-01 (x86) 可以获取该更正。
如果没有安装更新程序或补丁程序,一个临时解决办法是在包含头文件 <stdlib.h> 之前将标准头文件 <ctype.h> 也包含进来。
在模板中支持静态变量的 -instance=static 和 -instance=semiexplicit
早期版本的 C++ 编译器不支持模板中静态变量的静态实例化方法和半显式实例化方法。在 C++ 编译器 5.2 到 5.6 版本中并不存在此限制。
Extern 内联函数的函数局部静态变量的不同行为
在 ARM 规则里,外部内联函数的函数局部静态变量是文件静态的。而在 ISO 标准里,外部内联函数的函数局部静态变量是能够在多个编译单元之间共享的全局变量。
C++ 编译器的 5.0 和 5.1 版本在兼容模式 (-compat) 和标准模式(缺省模式)下实现了 ARM 定义的行为。而 C++ 编译器的 5.2 到 5.6 版本在兼容模式下实现了 ARM 定义的行为,而在标准模式下实现了 ISO 定义的行为。例如,
one.cc inline int inner() { static int variable = 0; return variable++; } int outer() { return inner(); } two.cc inline int inner() { static int variable = 0; return variable++; } int main() { return inner() + outer(); }以兼容模式 (-compat) 编译时,这两个变量的值不同,而且 main 的返回结果是 0(零)。
在标准模式(缺省模式)下编译时,这两个变量的值相同,而且 main 的返回结果是 1(一)。要在标准模式下得到前面的结果,应将内联函数声明为静态。
不再忽略模板语法错误
下面的模板语法是非法的,但 Sun C++ 编译器 4 和 5.0 版本并不报告这个错误。在标准模式(缺省模式)下 C++ 编译器 5.1 到 5.6 版本会报告这个语法错误。
template<class T> class MyClass<T> { ...}; // definition error template<class T> class MyClass<T>; // declaration error在这两种情况下,“MyClass<T>”中的“<T>”无效,必须将其删除,如下例所示,
template<class T> class MyClass { ...}; // definition template<class T> class MyClass; // declaration
E. 问题和解决办法
本节讨论了已知的软件问题及其可能的解决方法。关于更新和补丁程序,请查看更新信息,网址为 http://developers.sun.com/prodtech/cc/support_index.html。
- 当 -xipo 或 -xcrossfile 带有 -instances=static 时链接失败
- 预处理的 .i 文件会产生编译器错误
- 跨语言链接错误
- 名称损坏链接问题
- 调试工具错误地报告成员函数有多余的前导参数
- 不支持引用定义在模板中的非全局名称空间对象
- 定义在名称空间内的 #pragma align 要求损坏名称
- 函数重载解决方案
- 在 Solaris 8 操作系统中调试使用了交替线程的多线程 C++ 程序时,程序会挂起
如果将 -xipo 或 -xcrossfile 与 -instances=static 组合,链接会失败
模板选项 -instances=static(或 -pto)在与 -xcrossfile 或 -xipo 选项组合时不工作。使用该组合的程序会经常发生链接失败。
如果使用 -xcrossfile 或 -xipo 选项,就请使用缺省的模板编译模型 -instances=global。
通常,不要使用 -instances=static(或 -pto)。它不再有任何好处,但却有 C++ 用户指南 中描述的缺点。
预处理的 .i 文件会产生编译错误
__global 是 C++ 5.5 新增的关键字,它是新的 xldscope 编译器选项的一部分。如果使用旧版的编译器,将生成一个经过预处理的文件,一个 .i 文件,然后使用版本 5.5 或 5.6 来编译该 .i 文件,如果关键字 __global 在该 .i 文件中用作标识符,编译器会报告错误消息。
临时解决这个问题的一个方法是,在该 .i 文件的最开始加上 #pragma disable_ldscope。如果程序代码是为旧版编译器写的,就不会用到新链接器作用域关键字,例如 __global。如果它被其他的文件包含,则可以将 #pragma enable_ldscope 加到 .i 文件的末尾。
跨语言链接错误
如果执行 -xlang=f77 命令,则编译过程会遇到一个链接错误。为了避免这个错误,并且仍然可以使用相应的运行库,应该执行 -xlang=f77,f90。
名称损坏链接问题
下面的情况会导致链接问题。
- 函数在一个地方声明为带有一个常数参数,而在另一地方声明为带有一个非常数参数。
示例:
void foo1(const int); void foo1(int);这两个声明是对等的,但编译器在损坏这两个名称时却会不同处理。要避免这个问题就不能将值参声明为 const。例如,在任何地方都使用 void foo1(int);,包括该函数定义体。
- 函数有两个具有相同复合类型的参数,但只有一个参数是用 typedef 声明的。
示例:
class T; typedef T x; // foo2 has composite (that is, pointer or array) // parameter types void foo2(T*, T*) void foo2(T*, x*); void foo2(x*, T*); void foo2(x*, x*);所有的 foo2 声明都是对等的,而且应该损坏成相同的名称。然而编译器会对部分声明进行不同的处理。为了避免这个问题,应该统一使用 typedefs。
如果您无法统一使用 typedefs,一个临时解决方法是在定义该函数的文件中使用弱符号,使得声明与函数的定义一致。例如:
#pragma weak "__1_undefined_name" = "__1_defined_name"
注意—某些损坏名称依赖于目标体系结构。(例如,在 SPARC V9 体系结构中, size_t 是 unsigned long,在其他体系结构中则是 unsigned int。)在这种情况下,就会出现两个版本的损坏名称,分别对应两个模式。这时必须使用两个 pragma,并用适当的 #if 指令对其进行控制。
有关更多信息,请参见《C++ 迁移指南》。要查看 HTML 形式的本指南,请使用浏览器访问 file:/opt/SUNWspro/docs/index.html。
注意—如果 Sun Studio 9 编译器和工具未安装在缺省 /opt 目录,请询问系统管理员以了解系统中的实际安装路径。
调试工具错误地报告成员函数有多余的前导参数
在兼容模式 (-compat) 下,C++ 编译器会对成员函数指针的链接名进行错误地损坏处理。这个错误会导致 demangler 以及其他一些调试工具(例如 dbx 和 c++filt)报告该成员函数有多余的前导参数,包括对该成员函数所在类的引用。为了避免这个问题,要加上 -Qoption ccfe -abiopt=pmfun1 标记。要注意的是,带有这个标记的源代码进行编译后可能会与没有带这个标记的源代码在二进制级不兼容。在标准模式(缺省模式)下,损坏名称的处理不会有问题。
不支持引用定义在模板中的非全局名称空间对象
使用了模板和静态对象的程序会引起未定义符号的链接时间错误。编译器目前尚不支持对定义在模板中的非全局名称空间作用域对象的引用。考虑以下示例:
static int k; template<class T> class C { T foo(T t) { ... k ... } } };在这个例子中,一个模板类的成员引用了静态名称空间中的变量。记住,名称空间包含文件作用域。编译器不支持模板类的成员引用静态名称空间的变量。另外,如果模板在其他的编译单元实例化,那么每个实例都会指向不同的 k,这破坏了 C++ 定义一次规则,代码的行为将会不可预测。
下面的方法也是可行的,但这依赖于您如何使用 k,以及它应该有的功能。第二个选项仅可供属于类成员的函数模板使用。
- 可以使这个变量具有外部链接属性:
int k; // not static所有的实例都使用同一个 k。- 也可以使这个变量成为类的静态成员:
template<class T> class C { static int k; T foo(T t) { ... k ... } } };静态类成员有外部链接属性。每一个 C<T>::foo 的实例都使用不同的 k。而 C<T>::k 的一个实例可以被其他函数共享。这个选项也许就是您想要的。可以使这个变量具有函数局部化属性:
template<class T> class C { T foo(T t) { static int k; ... k ... } } };每一个 C<T>::foo 的实例使用它自己的 k 副本,它在函数外不可见。
定义在名称空间内的 #pragma align 要求损坏名称
当在名称空间里使用 #pragma align 时,必须使用损坏名称。例如,在下面的代码中,#pragma align 语句不会有任何作用。要避免这个问题,应该用 a、b 和 c 的损坏名称代替它们在 #pragma align 语句中的定义。
namespace foo { #pragma align 8 (a, b, c) // has no effect //use mangled names: #pragma aling 8 (__1cDfooBa_, __1cDfooBb_, __1cDfooBc_) static char a; static char b; static char c; }函数重载解决方案
早期发行版本的 C++ 编译器并不支持 C++ 标准要求的函数重载。当前发行版本解决了调用重载函数时出现的很多错误。具体来讲,当函数调用出现二义性时,编译器不会报错,但在没有二义性的情况下,编译器反而会警告该调用有二义性。
采用临时解决方法来避免错误的二义性消息已经没有必要了。也许您会看到以前没有的新二义性错误。
导致函数调用二义性的一个主要原因是仅重载一部分内置类型。
int f1(short); int f1(float); ... f1(1); // ambiguous, "1" is type int f1(1.0); // ambiguous, "1.0" is type double为了解决这个问题,要么完全不重载 f1,要么重载所有没有进行提升的类型:int、unsigned int、long、unsigned long 以及 double。(也许还有 long long、unsigned long long 以及 long double。)
另一个主要原因是类中的类型转换函数,特别是有重载运算符时。
class T { public: operator int(); T(int); T operator+(const T&); }; T t; 1 + t // ambiguous这个操作有二义性是因为它可能被处理成:
T(1) + t // overloaded operator 1 + t.operator int() // built-in int addition可以提供重载运算符,也可以提供类型转换函数,但同时提供它们就会造成二义性。
实际上,类型转换函数自身也经常会导致二义性,而且往往在不应该作转换的地方进行转换。如果您确实需要类型转换,最好使用有名称的函数,而不要使用类型转换函数。例如,使用 int to_int(); 来代替 operator int();。
进行这个修改后,1 + t 操作就不再具有二义性了。它只能解释为 T(1) + t。如果您希望有其他的解释,必须写成
1 + t.to_int()。在 Solaris 8 操作系统中调试使用了交替线程的多线程 C++ 程序时,程序会挂起
在 Solaris 8 操作系统中调试用 /usr/lib/lwp/ 中的备用线程构建的多线程 C++ 程序时,程序会挂起。32 位多线程 C++ 程序如果编译时指定 -R /usr/lib/lwp,在 dbx 中运行时也会挂起。64 位多线程 C++ 程序如果编译时指定 -R /usr/lib/lwp/sparcv9,也有可能会挂起,特别是使用运行时检查时。
这个现象只出现在以标准模式(缺省)(指定 -compat=5 编译选项)编译的 C++ 代码;而不出现在以兼容模式编译的代码(指定 -compat 编译选项)。
如果您考虑使用备用线程库进行性能调整,就请先用缺省线程库调试多线程程序,然后使用备用线程库。
该问题只在 Solaris 8 中发生。
F. 限制和不兼容
本节讨论系统或其他软件的限制和不兼容。有关该发行版本 Sun ONE Studio 9 的最新信息,请参见《Sun Studio 9 发行说明》。发行说明可在 Sun Studio 9 网站上找到,网址是:http://developers.sun.com/prodtech/cc/ss9/reference/docs/releasenotes.pdf。发行说明中的信息会更新和扩展所有自述文件中的信息。
-xia 和 -library=stlport4 之间不兼容
不能和 STLport C++ 库一同使用 C++ 区间数学库。只能按照《C++ 区间运算编程参考》中的说明编译和链接使用 -xia 选项的程序。
C++ 共享库补丁程序
每个 Solaris 操作环境版本都有相应的 SUNWlibC 补丁程序,Sun Studio 9 发行版本为每个它所支持的平台都提供了补丁程序。这个补丁程序不仅仅要安装到进行编译的系统,还要安装到所有运行程序的系统。没有这些补丁程序,有些程序会不能进行链接,有些程序会因为运行时错误而不正常结束。例如,链接器也许会报告类似下面的消息:
Undefined symbol First referenced in file std::ostream &operator<<(std::ostream&,const RWCString&) test.o ld:fatal:Symbol referencing errors.No output written to test也许还会看到下面的错误消息:
Hint:try checking whether the first non-inlined, non-pure virtual function of ...有关该 Sun Studio 9 版本的必需和可选补丁程序的信息,请参见 Sun Studio 9 网站,地址为 http://developers.sun.com/prodtech/cc/support_index.html。
编译器版本不兼容
本节的最后介绍 C++ 编译器 4.0 版本、4.1 版本、4.2 版本以及下列版本之间的不兼容性:
- Sun WorkShop C++ (5.0) 编译器
- Forte Developer 6 C++ (5.1) 编译器
- Forte Developer 6 update 1 C++ (5.2) 编译器
- Forte Developer 6 update 2 C++ (5.3) 编译器
- Forte Developer 7 C++ (5.4) 编译器
- Sun Open Net Environment (Sun ONE) Studio 8 C++ (5.5) 编译器
- Sun Studio 9 C++ (5.6) 编译器
- 缓存版本的不一致可能导致编译错误
- C++ 接口不兼容
- 使用 Tools.h++
- 使用多模板库;忽略 -ptr 选项
- 与包含有指向 const 成员函数的指针的 4.0.1 Libraries 相链接
- 与早期版本编译器生成的库相链接
- 来自不同版本的混合目标代码
缓存版本的不一致可能导致编译错误
当更改编译器时,必须在每个包含 SunWS_cache 子目录的目录下运行 CCadmin -clean(或者也可以使用 rm -rf SunWS_cache)。如果不这样做会导致下面的编译错误:
- SunWS_cache:Error:Database version mismatch
<path>/SunWS_cache/CC_version.
- "<path>/SunWS_cache/CC_state",
line 3:Error:"" not allowed here.** Assertion ** : 0
C++ 接口不兼容
C++ 编译器版本 5.0 到 5.6 与 4.0、4.1 以及 4.2 在二进制级不兼容,除非使用 5.0 到 5.6 编译器时指定 -compat 选项。不兼容是类布局、调用顺序以及实现 ANSI/ISO C++ 所要求的名称损坏的改变导致的。
5.0 到 5.6 版本的 C++ 编译器在二进制级兼容。
有关更多信息,请参见《C++ 迁移指南》。要查看 HTML 形式的本文档,请使用浏览器访问 file:/opt/SUNWspro/docs/index.html。Solaris 平台上的缺省安装目录是 /opt。如果没有在缺省 /opt 目录中安装 Sun Studio 9 软件,请询问系统管理员以了解系统中的实际安装路径。
使用 Tools.h++
C++ 编译器缺省时会使用标准 iostreams。如果在标准模式下使用 Tools.h++,必须指定 -library=rwtools7_std 选项,或者包含 libiostream,如下所示:
example% CC -library=rwtools7_std foo.cc -> uses standard iostreams example% CC -library=rwtools7,iostream foo.cc -> uses classic iostreams然而,在兼容模式下(指定 -compat 编译选项),不能执行 -library=rwtools7_std,因为没有可用的标准库:
example% CC -compat foo.cc -library=rwtools7 -> compatibility mode, standard library not available不要与 -library=stlport4 一起指定 -library=rwtools7、-library=rwtools7_dbg、-library=rwtools7_std 或者 -library=rwtools7_std_dbg。Tools.h++ 不支持 STLport。
选项 -library=rwtools7_std 和 -library=rwtools7、iostream 生成的二进制代码不兼容。如果使用这些选项中的一个,就应该将每个 CC 命令上同样的选项用于编译和链接。
有关更多信息,请参见《C++ 迁移指南》。要查看 HTML 形式的本指南,请使用浏览器访问 file:/opt/SUNWspro/docs/index.html。Solaris 平台上的缺省安装目录是 /opt。如果没有在缺省 /opt 目录中安装 Sun Studio 9 软件,请询问系统管理员以了解系统中的实际安装路径。
使用多模板库;忽略 -ptr 选项
注意—缺省情况下不再创建模板存储库。必须显式指定 -instances=extern 以使编译器创建存储库。
在 C++ 编译器 5.0 版本以前, -ptr 标记用来为模板实例指明库。在 5.0 到 5.6 版本中,不再使用 -ptr 标记,因为编译系统可以从所读的对象文件对应的模板库读取,也可以将模板实例写入 CC 命令指定的输出位置包含的库。
在 5.5 版 C++ 编译器中 -ptr 选项已作废。现在编译器忽略了 -ptr 选项。虽然编译器会忽略该选项,您仍应该从所有的编译命令里删除 -ptr ,因为也许在新的发行版里它又会有新的行为特性。
注意—以前版本不支持在多个应用程序或者库间共享一个模板库,当前版本也不支持。如果试图这样做,会因为模板重复定义而导致编译错误以及运行时不可预知的结果。有关更多信息,请参见《C++ 用户指南》。
要查看 HTML 形式的本指南,请使用浏览器访问 file:/opt/SUNWspro/docs/index.html。Solaris 平台上的缺省安装目录是 /opt。如果没有在缺省 /opt 目录中安装 Sun Studio 9 软件,请询问系统管理员以了解系统中的实际安装路径。
与包含有指向 const 成员函数的指针的 4.0.1 Libraries 相链接
4.0.1 版 C++ 编译器为 const 成员函数指针生成的损坏名称与 4.1、4.2 以及 5.0 到 5.6 版 C++ 编译器的都不一样。如果您在使用这个版本的编译器,并且不能与 4.0.1 生成的、包含有这样名称的库相链接,应该要么重新编译库,要么在编译其他程序时使用 -compat -Qoption ccfe -abirel=4.0.1 选项。
注意—以后的发行版本也许不支持 -abirel=4.0.1 选项。
与早期版本编译器生成的库相链接
带有外部“C”函数的模板实例不能识别 C++ 4.0.1 和 C++ 4.1 编译器生成的损坏名称。导致的结果是调试工具会出错。我们已经改正了这个问题,但仍有些用户不能将 5.0 到 5.6 生成的目标文件与早期编译器生成的库相链接。出现这种不兼容性的可能性极小,但一旦出现,您可以采取以下两种方法之一进行处理:
- 使用 Sun Studio 9 C++ (5.6) 编译器重新编译库
- 使用 Sun Studio 9 C++ (5.6) 编译器编译新的目标文件,同时指定 -compat 和 -Qoption ccfe -abirel=4.1 标记。
注意—以后的发行版本也许不支持 -abirel=4.1 标记。
来自不同版本的混合目标代码
可以在同一程序中将来自不同 C++ 编译器的目标代码混合起来,前提是不能将兼容模式和标准模式的代码相混合。然而,在链接接最终的程序时,必须使用在该混合版本中的最新编译器。
注意—不能链接 4.2 和标准模式的 C++ 代码。
G. 文档错误
目前没有新的信息。
H. 可发送库
- 如果可执行文件使用列在以下命名文件中的 Sun 动态库,那么许可证中就包括了将库给重新分发客户机的权利。
???/opt/SUNWspro/READMEs/runtime.libraries
注意—如果未将 Sun Studio 9 软件安装到 /opt 目录中,请询问系统管理员以了解系统中的实际安装路径。
您不能以任何形式重新分发或透漏对象模块的头文件、源代码、对象模型或静态库。
“使用许可证”出现在“最终用户对象代码许可证”中,可以在 CD-ROM 塑料包装盒背面看到。
- 如果您希望使用 libCstd 和/或 libiostream 的共享库版本,有两个选择:
- 与您的产品一起分发 SUNWlibC 补丁程序。
- 要求您的客户从 Sun 网站上下载最新的 SUNWlibC 补丁程序,网址为 http://www.sunsolve.sun.com。补丁程序是免费的,可以随意重新分发。
和以前一样,如果您选择静态链接任意一个库,就没有这些要求和限制了。要确保您的程序在不同版本的操作系统上的兼容性,请与共享库版本建立链接。
I. 未实现的标准
C++ 编译器支持 ISO C++ 标准,ISO IS 14882:1998,编程语言 C++。下面列出了标准要求而当前发行版本并不支持的功能:
- 函数模板的参数中出现包含有非类型模板参数的表达式,例如
template<int I> void foo(mytype<2*I> ) { ... } }
- 对模板参数模板化(作为正式模板参数的模板)
- 通用字符名
- 模板编译的输出模式
- 为了保持当前 C++ 编译器发行版本与以往版本的兼容性,有些 libCstd 函数没有实现。有关更多信息,请参见 C++ 常见问题解答链接,网址为 file:/opt/SUNWspro/docs/index.html。Solaris 平台上的缺省安装目录是 /opt。如果没有在缺省 /opt 目录中安装 Sun Studio 9 软件,请询问系统管理员以了解系统中的实际安装路径。
版权所有© 2004 Sun Microsystems, Inc. 保留所有权利。必须依据许可证条款使用。