【问题标题】:__attribute__((init_priority(X))) in GCC__attribute__((init_priority(X))) 在 GCC
【发布时间】:2010-07-30 13:36:48
【问题描述】:

我在 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 移植一个非常大的项目。

【问题讨论】:

  • 感谢 C++ 让这个噩梦彻底崩溃。这只是这种糟糕语言的众多问题之一。
  • 这里的问题不是语言,而是架构。它是一种很棒的编程语言,但并非所有开发人员都知道如何使用它。
  • 程序的入口点无法以任何标准方式确定,这怎么不是语言的错?像程序起点这样基本的东西应该可以用任何体面的语言轻松识别。
  • @Dan 该语言的入口点实际上是main,为了避免这些初始化问题,您所要做的就是避免以翻译单元之间交互的方式使用全局/静态数据。如果您正在创建足够多的全局/静态数据而遇到问题,那么您几乎肯定应该重新考虑您的设计。
  • 如果你移植这段代码,你怎么知道它在VS中总是以正确的顺序工作?如果您升级编译器版本并更改顺序怎么办?我认为实际上重构将使两个端口都变得更好,并且如果按步骤完成应该是可管理的。

标签: c++ gcc static initialization


【解决方案1】:

gcc 文档 (gcc 4.4) 说:

`init_priority(优先级)'

在标准 C++ 中,保证在命名空间范围内定义的对象 严格按照顺序初始化 它们的定义在给定的翻译单元中。没有保证 用于跨翻译单元的初始化。然而,GNU C++允许用户控制对象的初始化顺序 在命名空间范围内使用 `init_priority' 属性定义 指定一个相对优先级,一个常数积分表达式 目前介于 101 和 65535 之间。较低的数字 表示更高的优先级。

没有任何迹象表明这如何适用于库,尤其是共享库。我希望静态库(libxyz.a)在这方面与单个目标文件一样工作,因为它们只是目标文件的集合,并且文档的措辞表明它可以跨翻译单元(即使用不同的对象文件)。

但是,共享库本身就是有效的可执行文件 --- 在给定的共享库中,初始化是按照指定的顺序完成的,但是共享库是按照动态加载程序(即 liba)指定的顺序作为一个整体进行初始化的。 so 根据加载器的排序标准在 libb.so 之前或之后加载,并且 init_priority 属性不会影响该排序。

【讨论】:

    【解决方案2】:

    如果你的库是动态的,即 .so 而不是 .a,那么ld 会影响事物的顺序,而 gcc 只能控制同一个 ELF 二进制文件中的 init 的顺序(这将是所有.o 和 .a)。

    【讨论】:

      【解决方案3】:

      如果您希望按顺序初始化您的事物,请尝试使用 __attribute__((constructor (priority))) 构建一个 init 函数。

      【讨论】:

        【解决方案4】:

        使用 GNU 链接器,您的共享库将按照它们的依赖顺序一一初始化,而不是并行初始化。这意味着如果您的二进制文件依赖于共享库,则共享库会在二进制文件中的动态初始化开始之前进行初始化。

        【讨论】:

          【解决方案5】:

          所有有问题的对象是否都在同一个命名空间范围内(我假设是全局的)?我在 GCC 文档中没有看到任何保证这需要跨库工作(尽管链接器这样做是有意义的)。

          尽管您有最后的说明,但我仍然建议重构。如果您可以控制使用__attribute__ 的代码,那么您至少可以使用一个使用静态本地的包装“实例”函数来进行初始化。这将需要一些代码更改,但通常它应该能够以半自动的方式完成。见http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.13

          另外请注意,如果您修复/重构代码,您不会冒编译器补丁/更新到您的 VS 编译器的风险,可能会以不明显的方式突然破坏代码。

          【讨论】:

            猜你喜欢
            • 2013-08-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-24
            • 2019-07-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多