为什么未命名的结构内联变量在每个翻译单元中没有相同的地址?

Why does an unnamed struct inline variable not have the same address in every translation unit?

本文关键字:单元 地址 翻译 结构 未命名 变量 为什么      更新时间:2023-10-16

thing.hpp

struct
{
} inline thing;

other.cpp

#include "thing.hpp"
#include <cstdio>
void test()
{
std::printf("test: %pn", &thing);
}

main.cpp

#include "thing.hpp"
#include <cstdio>
extern void test();
int main()
{
std::printf("main: %pn", &thing);
test();
}

在 C++17 模式下使用 Clang 11 或 GCC 9.3.0 编译时,输出如下所示:

main: 0x404031
test: 0x404032

根据我的理解,具有相同定义的内联变量在每个翻译单元中都应该具有相同的地址.
给结构类型命名会导致地址相同。

为什么thing在不同的翻译单元中没有相同的地址?

让我们暂时忽略内联说明符。想象一下它缺席了。您的代码仍会产生相同的结果。原因是类类型本身的链接。

[basic.link]

8 当且仅当以下情况下,称为类型具有链接:

  • 它是命名的类或枚举类型(或具有用于链接目的的名称 ([dcl.typedef]((,并且该名称具有链接;或
  • 它是一个未命名的类或
  • 未命名的枚举,它是具有链接的类的成员;或
  • 它是类模板(子句 [temp](35 的专用化;或
  • 它是一种基本类型;或
  • 它是类或
  • 枚举以外的复合类型,仅从具有链接的类型复合;或
  • 它是具有链接的类型的 CV 合格版本。

没有链接的类型不得用作变量的类型或变量的类型 与外部链接功能,除非

  • 实体具有 C 语言链接,或
  • 实体在未命名的命名空间中声明,或者
  • 实体未使用 ODR 或在同一转换单元中定义。

[ 注意:换句话说,没有链接的类型包含一个类或 不能在其翻译单元之外命名的枚举。一 使用此类类型声明具有外部链接的实体不能 对应于另一个翻译单元中的任何其他实体 程序,因此必须在翻译单元中定义,如果是 ODR 使用。另请注意,具有链接的类可能包含成员 其类型没有链接,并且 typedef 名称在 确定类型是否具有链接。 — 尾注 ]

如您所见,您使用的类类型没有链接。因此,在引用的段落下,由于您 odr-use 变量(具有外部链接(,因此必须在用于代码格式正确的同一翻译单元中定义它。这转化为包含该标头的不同翻译单元中的不同定义。

最终,无论是否使用内联说明符,这些定义都不能用于同一对象。所以你最终会看到不同的地址。