Saves space by not creating out-of-line copies of inline functions controlled by #pragma statements. Using this option will generate linker errors if the such functions are not inlined everywhere they are called
(GCC 4.02或以后)使g++不导出ELF(Executable and Linking Format,Linux和Solaris等系统上默认的2进制文件格式)中用hidden标识的object模块内或库内的符号。该选项能减少目标文件大小,加快符号表的查找,从而改善运行性能。但是,该选项也会因为不同的visibility等级而导致模块间抛出异常发生问题,详见后面的““Visibility Attributes and Pragmas for GCC C++ Libraries”一节。如果没有使用该选项,那么默认的visibility值是default,即导出所有目标文件和库里的符号。
当非模板的友元函数定义在模板里时不给出警告。In the C++ language template specification, a friend must declare or define a nontemplate function if the name of the friend is an unqualified identifier.
ABI Differences in g++ Versions C++ ABI是一套API标准,定义了C++库提供的数据类型、类、方法、头文件等的接口和规范。对库和目标文件来说,物理组织、参数传递方式和命名方式是很重要的,所以需要一个统一的接口,使编译出来的C++程序与提供的库的接口一致。这种一致性对语言特有的一些属性更加重要,比如抛出异常和捕捉异常的时候。 从版本3开始的GNU C++编译器,都遵循一个工业标准的C++ ABI规范,定义在http://www.codesourcery.com/cxx-abi/abi.html。虽然这个规范是为64位Itanium定制的,但是它适用于任何平台,并且已经作为GNU/Linux和BSD系统的C++ ABI的实现。 版本3.4以前的g++使用ABI版本1,之后使用ABI版本2。不同ABI版本之间的程序和库不能混用。如果你不确定自己g++的ABI版本,可以用g++ --version命令检查g++的版本,或用一个伪编译命令显示ABI标识符,命令行如下: g++ -E -dM - < /dev/null | awk '/GXX_ABI/ {print $3}' 如果显示102,那么就是版本1;如果显示1002,就是版本2。如果你必须用到以前版本ABI的库,那么给g++加上选项-fabi-version=n,其中n就是你要兼容的ABI版本。这样做只能算作权宜之计,把所有旧的代码和库更新到当前版本才是最佳解决方案。 GNU C++ Implementation Details and Extensions 本文虽然不讨论怎样写好C++程序,但是当你用GCC的C++编译器编译你的C++程序的时候,你可以从GCC的扩展中得到许多好处,包括编译器自身的优势和g++使用的标准C++库libstdc++的优势。本节提炼出最为重要的一些扩展特性,并讨论它们在C++规范和编译器行为方面的一些差异。 Attribute Definitions Specific to g++ 作为对visibility属性(详见于“Visibility Attributes and Pragmas for GCC C++ Libraries”)的补充,g++提供了2个额外的属性,即init_priority(priority)和java_interface属性。 The init_priority Attribute 该属性允许用户控制某个名字空间里的对象的初始化顺序。通常,对象的初始化顺序是它们在某个代码单元里的定义顺序。init_priority只有一个整型参数,值为101到65535,越小表示优先级越大。比如,在下面的伪码里,类MyClass将比类YourClass先初始化: class MyClass { … }; class YourClass { __attribute__ ((visibility("default"))) void MyMethod(); … }; 要改变它们的初始化顺序,你可以把代码改成下面这样: class MyClass { __attribute__ ((init_priority(65535))); … }; class YourClass { __attribute__ ((init_priority(101))); … }; 你只需要注意所使用的优先级数值的顺序,具体使用了哪个数值则无所谓(即只要MyClass的优先级数值比YourClass大就行了,是不是65535和101则无所谓)。 The java_interface Attribute 该属性通知g++某个类是一个Java接口类,并只能在标识了extern “Java”的模块内使用。调用这个类的函数使用的是GCC Java编译器的接口表机制(interface table mechanism),而不是通常的C++虚函数表机制(virtual function table mechanism)。 提示记住,Java的运行时环境需要更多的初始化工作。当你混合使用C++和Java代码时,最好用Java写主程序,这样能保证调用Java函数前初始化工作已经做足了。C++ Template Instantiation in g++ 模板是C++最有用和最有趣的特性之一,能减少重复代码,提高复用率,简化调试和代码维护工作。模板也有利于编译时的类型检查,比如,使用了模板就不用再传递void指针,因为你可以把模板参数实例化成任何需要的类型。 g++通过增加3个功能扩展了标准的ISO模板定义: l 支持使用extern关键词对实例化类型进行前置申明; l The ability to instantiate the support data required by the compiler for a named template class without actually instantiating it by using the inline keyword l The ability to only instantiate the static data members of a class without instantiating support data or member functions by using the static keyword 基本上,GCC的g++编译器支持Borland和Cfront(AT&T)两种模板特性。要支持Borland的模板实例化和使用特性,g++使用-frepo选项允许预处理器在处理每个翻译单元(源代码文件)时进行模板实例化,并把信息存在.rpo文件里。这些文件被后面的编译过程使用,并由链接器最后合并成单个编译单元。要支持Cfront特性,g++内置了一个模板实例化库并在链接的时候合并到代码里。Cfront要求使用模板的代码要么进行显式实例化,要么包含定义模板的申明文件。你可以把显式实例化放在代码的任何地方,或一个包含的头文件里。对于后者,你可能要去掉-fno-implicit-templates选项,这样你只得到了显式实例化的那些实例。 Function Name Identifiers in C++ and C GCC编译器预定义了2个标识符存储当前函数的标识。__FUNCTION__标识符只存储函数名字,__PRETTY_FUNCTION__则存储函数的全称。在C程序里,这2种名字是一样的,但是在C++程序里它们有区别。下面的程序展示了这种区别: #include <iostream> using namespace std; class c { public: void method_a(void) { cout<<"Function "<<__FUNCTION__<<" in "<<__FILE__<< endl; cout<<"Pretty Function "<<__PRETTY_FUNCTION__<<" in " << __FILE__ << endl; } }; int main(void) { c C; C.method_a(); return 0; } 运行的输出是: $ ./a.out Function method_a in FUNCTION_example.cc Pretty Function void c::method_a() in FUNCTION_example.cc 在C++里,__FUNCTION__和__PRETTY_FUNCTION__是变量,而不是宏定义,所以#ifdef __FUNCTION__是没有意义的。 注意如果你的GCC是3.2版本或更高,那么__FUNCTION__和__PRETTY_FUNCTION__的行为就和C99定义的__func__变量是一样的。早于3.2版本的GCC编译器把__FUNCTION__和__PRETTY_FUNCTION__定义成字符串,所以它们可以和其他字符串进行串接操作。Minimum and Maximum Value Operators g++编译器加入了<?和>?操作符,分别表示2个数值中较小的和较大的那个。比如,下面的代码把10赋给min变量: min = 10 <? 15; 而下面的代码把15赋给max: max = 10 >? 15; 提示既然这些操作符是语言提供的,那么它们也能对任何类或enum类型进行重载。Using Java Exception Handling in C++ Applications Java和C++的异常处理模型是不同的,虽然g++能猜测C++代码何时使用了Java异常,你最好还是明确标识出这种情况,避免链接错误。要告诉g++一块代码可能使用Java异常,把下面的代码放在该翻译单元中任何catch和throw代码之前: #pragma GCC java_exceptions 你不能在一个翻译单元里同时使用Java和C++异常。 Visibility Attributes and Pragmas for GCC C++ Libraries 写C++库的时候一个普遍的问题就是可见的ELF符号太多了,其实许多符号都不能被外部使用,也不用对外公开。GCC版本4.02及更高提供了-fvisibility=value选项和相关的内置属性,使你可以控制这种行为,使用的方式和微软C++编译器提供的__declspec(dllexport)方式相似。新的-fhidden选项有2个可选值:default,导出目标文件的所有符号(这也是默认的行为);hidden,不导出当前目标模块的符号。还可以在函数或类前加如下代码来进行设置:__attribute__ ((visibility("default")))和__attribute__ ((visibility("hidden")))。 默认情况下,ELF导出全部符号。要隐藏特定目标文件的符号,需要在编译该文件的时候加上-fvisibility=hidden选项。这将导致makefile的复杂性大大增加,因为你要么需要手动设置每个文件的编译选项,要么改变全局编译选项导致任何符号都不能导出。这在类库正常抛出异常或者调试某些变量的时候实在是个灾难。 让指定的符号可见的好方式是联合使用代码属性设置和编译选项-fvisibility=hidden。如果要导出某个符号,先在它们的定义前加上__attribute__((visibility("default"))),比如下面这样: class MyClass { int i; __attribute__ ((visibility("default"))) void MyMethod(); … }; 然后给makefile增加-fvisibility=hidden的编译选项,这样所有其他的符号就被隐藏了。另一个稍微好点的方法是定义一个宏,并放到所有你不想导出的符号定义前面,然后使用默认的导出所有符号,如下所示: #define LOCAL __attribute__ ((visibility("hidden"))) class MyClass { int i; LOCAL void MyMethod(); … }; 编译时不使用-fvisibility=value选项,这样除了MyMethod被隐藏,其他符号都被导出。 还有一种控制可见属性的pragma语法现在还能使用,不过将来可能要去掉,如下面这样: extern void foo(int); #pragma GCC visibility push(hidden) extern void bar(int); #pragma GCC visibility pop 符号foo会被导出,但是bar则不会。这种方式虽然很简单方便,但是建议你还是使用visibility和__attribute__。