行内变量是否跨界唯一?

Are inline variables unique across boundaries?

这是 的跟进。
正如对答案的评论中提到的:

An inline variable has the property that - It has the same address in every translation unit. [...] Usually you achieved that by defining the variable in a cpp file, but with the inline specifier you can just declare/define your variables in a header file and every translation unit using this inline variable uses exactly the same object.

此外,从答案本身来看:

While the language does not guarantee (or even mention) what happens when you use this new feature across shared libraries boundaries, it does work on my machine.

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

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

Is there any guarantee regarding the uniqueness of an inline variable when it is used across boundaries or is it simply an implementation detail that I should not rely on?

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

编译器显然无法检查这一点,链接器也不会打扰。因此,如果您对链接器撒谎(通过 而不是 执行上述操作),那么您最终会遇到麻烦。


好吧,既然不是每个人都明白我的意思'lie to the linker',我会充实一点。

@oliv 友善地提供了 this link,除此之外还说了这一点(我的评论):

Duplicate copies of these constructs [i.e. variables declare inline in multiple TU's] will be discarded at link time.

很好,这就是我们需要的。问题是,你不知道是哪一个(显然,只保留了一个,所以推而广之,你不知道会是哪一个)。

所以,如果它们不同,你不知道你最终会得到哪一个,所以你最终得到的是(一种特别阴险的形式) UB。这就是我所说的 'lie to the linker' 的意思。因为,通过在不同的 TU 中以不同的方式声明您的变量,这正是您所做的。哎呀!

这就是我对标准的解读。根据basic.link/1:

A program consists of one or more translation units linked together.

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

因此,根据我的解释,程序是动态链接还是静态链接并不重要,实现的行为应该是相同的:class 静态变量应该是唯一的(无论它是内联还是不是)。

在 Linux 上,这是真的。

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

C++ 目前没有共享库的概念。因此 inline 跨共享库的行为方式将是特定于实现和平台的。

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

多年来已经提交了很多建议来纠正这种情况(N1400, N1418, N1496, N1976, N2407, N3347, N4028), none of which took off the ground. It's just hard to implement in a generic way, and C++ generally tries to stay out of implementation details. As GCC put it:

For targets that do not support either COMDAT or weak symbols, most entities with vague linkage are emitted as local symbols to avoid duplicate definition errors from the linker. This does not happen for local statics in inlines, however, as having multiple copies almost certainly breaks things.

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