我在GCC中使用__attribute__((init_priority(X)))
,如下所示:
Type1 __attribute__ ((init_priority (101))) name1 = value1;
Type2 __attribute__ ((init_priority (102))) name2 = value2;
在不同的源文件中。我们说file1.cpp和file2.cpp。 如果我在同一个库中使用它,它按预期工作,name1在name2之前初始化,但如果我在不同的库中使用它,初始化的顺序不是预期的。我在gcc文档中读到,这应该像我期望的那样在不同的库中工作,以定义初始化的顺序。我使用它的方式有什么问题吗?你有同样的问题吗?
PS:重构不是这个问题的解决方案,因为我必须从Visual Studio移植一个非常大的项目。
答案 0 :(得分:7)
gcc文档(gcc 4.4)说:
`init_priority(PRIORITY)'
在标准C ++中,保证在命名空间范围内定义的对象 按照严格按照的顺序进行初始化 他们在给定翻译单元中的定义 。不保证 用于翻译单元的初始化。但是,GNU C ++允许用户控制对象的初始化顺序 在命名空间范围内使用`init_priority'属性定义 指定相对PRIORITY,常量积分表达式 目前约束在101和65535之间。数字越来越少 表示更高的优先级。
对于库,尤其是共享库,没有任何迹象表明这是如何适用的。我希望静态库(libxyz.a)在这方面与单个目标文件的工作方式相同,因为它们只是目标文件的集合,文档的措辞表明它适用于翻译单元(即具有不同的对象)文件)。
但是,共享库本身就是有效的可执行文件 - 在给定的共享库中,初始化按指定的顺序完成,但共享库按动态加载器即liba指定的顺序初始化。所以在libb.so之前或之后根据加载器的排序条件加载,init_priority属性不会影响该排序。
答案 1 :(得分:0)
如果你的库是动态的,即.so而不是.a,那么ld
将影响事物的顺序,而gcc只能控制同一个ELF二进制内的init的顺序(这将是总和所有.o和.a的)。
答案 2 :(得分:0)
答案 3 :(得分:0)
使用GNU链接器,您的共享库将按其依赖项的顺序逐个初始化,而不是并行。这意味着如果您的二进制文件依赖于共享库,则在二进制文件中动态初始化开始之前,共享库将被初始化。
答案 4 :(得分:0)
所有相关的对象是否都在相同的命名空间范围内(我假设是全局的)?我没有在GCC文档中看到任何保证在库之间工作所需的保证(尽管链接器这样做是有意义的。)
尽管你最后的说明,我仍然会建议重构。如果您可以控制使用__attribute__
的代码,那么您至少可以使用包含静态本地的包装“实例”函数来进行初始化。它需要一些代码更改,但一般来说它应该能够以半自动的方式完成。请参阅http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.13。
另请注意,如果您修复/重构代码,则不会冒险对VS编译器进行编译器补丁/更新,从而突然破坏代码,可能是以非显而易见的方式。