【问题标题】:Template instantiation - How do compilers avoid duplicate symbols?模板实例化 - 编译器如何避免重复符号?
【发布时间】:2017-11-25 19:01:48
【问题描述】:

假设我有一个人为的头文件,其中包含一个模板类和两个包含完全相同的模板类实例化的源文件,以及一个重复的函数。那就是……

人为的头文件(thing.hpp):

#pragma once

template <typename T>
class Thing {
  public:
    T t;
  public:
    T& value() {
        return t;
    }
};

thing.cpp:

#include <thing.hpp>

template class Thing<int>;

int MeaningOfLife() {
    return 42;
}

thingy.cpp:(和thing.cpp一模一样)

在编译和链接时(在 OS X 上使用 clang),似乎只有 MeaningOfLife 被视为重复符号,但模板实例化的符号(只是 Thing::value())不是。仔细检查反汇编后,似乎在Thing::value() 的符号上放置了一个汇编指令,称为.weak_definition

问题 0:暗示该指令正在做一些事情来防止符号被多重定义,但它到底在做什么?

问题 1:其他编译器如何在其他地方(例如 Linux、Windows 等)完成此操作?

问题 2:如果我错误地更改了其中一个重复模板实例的汇编代码会怎样?即相同的符号,不同的功能体。智能编译器会检测到差异吗?

【问题讨论】:

  • 我相信您的所有问题都在this 线程中得到了解答。

标签: c++ macos templates clang


【解决方案1】:

粗略的 Google 搜索将我们带到these OSX docs,其中指出:

.weak_definition 指令导致 symbol_name 成为弱定义。 symbol_name 只能在 coalesced 部分中定义。 C++ 编译器使用它来支持模板实例化。 [...]

它继续定义coalesced

coalesced 部分可以包含任何指令或数据,并且在链接在一起的多个目标文件中可以定义多个符号定义时使用。静态链接编辑器保留与它链接的第一个目标文件中的合并符号相关联的数据,并默默地丢弃来自其他目标文件的数据。 coalesced 部分的一个示例是编译器为 C++ 模板的隐式实例化生成代码的部分。

我不知道如果您修改其中一个定义会发生什么(我没有尝试过),但文档暗示链接器只是盲目地采用它首先找到的任何一个。

【讨论】:

  • 我之前看到过这个,但这似乎是 OS X 特有的。我想知道其他系统可能会做什么。
  • @MonatheMonad 其他系统也会做类似的事情。语言规范允许模板类型的多种定义。它们应该都匹配,但如果它们不匹配,编译器(链接器)将首先找到它,并且不需要发出诊断。
猜你喜欢
  • 2017-06-19
  • 2018-06-02
  • 2014-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-10
  • 2019-11-23
  • 1970-01-01
相关资源
最近更新 更多