代码之家  ›  专栏  ›  技术社区  ›  skypjack

内联变量跨边界是否唯一?

  •  18
  • skypjack  · 技术社区  · 6 年前

    这是对 this question .
    如答案注释所述:

    内联变量具有以下属性:- 每个翻译单元都有相同的地址 . […]通常通过在cpp文件中定义变量来实现这一点,但是使用内联说明符,您可以在头文件中声明/定义变量,并且使用该内联变量的每个翻译单元都使用完全相同的对象。

    此外,从答案本身来看:

    虽然语言不能保证(甚至提到)当您跨共享库边界使用这个新特性时会发生什么,但它确实在我的机器上工作。

    换言之,当涉及共享库时,不清楚是否保证内联变量跨边界是唯一的。有人凭经验证明 它起作用了 在某些平台上,但这并不是一个正确的答案,它可能会破坏其他平台上的一切。

    当内联变量跨边界使用时,是否有任何关于其唯一性的保证,或者它只是一个我不应该依赖的实现细节?

    3 回复  |  直到 6 年前
        1
  •  8
  •   geza    6 年前

    这就是我如何解释标准。根据 basic.link/1 :

    程序由一个或多个链接在一起的翻译单元组成。

    它既不说静态链接,也不说动态链接。程序是连接在一起的翻译单元。链接是否分两步完成并不重要(首先创建.dll/.so,然后创建动态 链接器 将所有动态libs+可执行文件链接在一起)。

    所以,在我的解释中,不管程序是动态链接还是静态链接,实现的行为都应该相同:类静态变量应该是唯一的(不管它是内联的还是非内联的)。

    在Linux上,这是真的。

    在Windows上,这在所有情况下都不起作用,因此在我的解释中,它违反了这些情况下的标准(如果创建一个单独的.dll,其中包含静态、非内联变量,以及所有其他.dll和exe引用此变量,它就起作用)。

        2
  •  5
  •   rustyx    6 年前

    C++目前没有共享库的概念。那就这样吧 inline 跨共享库的行为将是特定于实现和平台的。

    事实上 [basic.link]/1 声明: 程序由一个或多个链接在一起的翻译单元组成。 “并不意味着与另一个已经链接的模块链接在一起的程序的行为应该相同。

    这些年来,已经提出了许多改善这一状况的建议。( N1400 , N1418 , N1496 , N1976 , N2407 , N3347 , N4028 没有一个从地上掉下来。很难用通用的方式来实现,C++通常试图避开实现细节。作为海湾合作委员会 put it :

    对于既不支持COMDAT也不支持弱符号的目标,大多数具有模糊链接的实体都作为本地符号发出,以避免来自链接器的重复定义错误。但是,对于内联中的本地静态,这不会发生,因为拥有多个副本几乎肯定会破坏某些内容。

    默认情况下,MSVC不公开任何符号。任何“外部”符号都需要使用特定于平台的显式声明 __declspec(dllexport) . 因此,不能声称Windows与C++是不兼容的。这里没有违反C++规则的原因,因为没有任何规则。

        3
  •  1
  •   1201ProgramAlarm    6 年前

    当内联变量跨边界使用时,是否有任何关于其唯一性的保证,或者它只是一个我不应该依赖的实现细节?

    由你来确保这一点(通过确保所有的声明事实上是相同的)。

    编译器显然不能检查这个,链接器也不麻烦。所以如果你对链接器撒谎 这样做),你就会陷入麻烦。


    好吧,因为不是每个人都明白我所说的“对链接器撒谎”的意思,我会把它充实一点。

    @奥利弗,请提供 this link ,其中包括以下内容(我的评论):

    链接时将丢弃这些构造的重复副本[即变量在多个tu中内联声明]。

    很好,这就是我们需要的。问题是, 你不知道哪一个 (很明显,只保留了一个,所以通过扩展,您不知道会是哪个)。

    所以, 如果他们不同 你不知道最后会是谁,所以你最终会是(一种特别阴险的形式)乌布。这就是我所说的“对链接者撒谎”。因为,通过在不同的tu中声明不同的变量,这正是您所做的。哎呀!