【问题标题】:ODR and internal linkageODR 和内部链接
【发布时间】:2019-08-11 10:58:40
【问题描述】:

假设我在一个程序中有两个编译单元,每个编译单元都声明了一个签名相同但实现不同的非内联函数,例如

// a.cpp
namespace internal {
    int foo(int a) {
        return a+1;
    }
}

int main() {
}

// b.cpp
namespace internal {
    int foo(int b) {
        return b+2;
    }
}

编译/链接这个(g++ 4.8.3 with -std=c++11),我得到一个错误

b.cpp:(.text+0x0): multiple definition of `internal::foo(int)'

这是意料之中的,因为据我所知,这只是违反one definition rule

每个非内联函数或变量的一个且只有一个定义 odr-used(见下文)必须出现在整个 程序(包括任何标准和用户定义的库)。

现在,将 namespace internal 更改为未命名的命名空间,错误就消失了。直观地说,这对我来说很有意义,因为我正在从 external to internal linkage 更改函数:

在命名空间范围内声明的以下任何名称都具有外部 除非命名空间未命名或包含在 未命名的命名空间 (C++11 起):未列出的变量和函数 上面(即未声明为静态的函数 [...])...

[A]在未命名的命名空间或命名空间中声明的所有名称 在一个未命名的命名空间中,即使是显式声明的外部命名空间, 有内部联系。

但是,我无法在一个定义规则中找到任何内容,该规则将具有内部链接的函数排除在外。因此,我的问题是:我的直觉推理是否正确,还是我仍然违反具有内部链接的函数的单一定义规则(并且编译器/链接器不再报告它)?此外,标准(或 cppreference.com :))在哪里说明它是否可以?

【问题讨论】:

  • 你的直觉是对的。从标准中寻找细节只会加强它。如果您从事语言律师,这是一个很好的目标。

标签: c++ c++11 linkage one-definition-rule


【解决方案1】:

n4713

§6.5 程序和链接 [basic.link]

当一个名字可能表示同一个对象时,它被称为具有链接, 引用、函数、类型、模板、命名空间或值作为名称 由另一个范围内的声明引入:

(2.1) — 当名称具有外部链接时,它表示的实体可以是 由来自其他翻译单元范围的名称或来自 同一翻译单元的其他范围。

(2.2) — 当名称具有内部链接时,它所表示的实体可以 在同一翻译中被其他范围的名称引用 单位。

——当一个名字没有链接时,它表示的实体不能被引用 来自其他范围的名称。

这基本上是说(在未命名的命名空间的情况下)来自a.cpp 的名称foo 和来自b.cpp 的名称foo 各自指代不同的实体。所以你没有同一个对象的两个定义,所以不会违反 ODR。

【讨论】:

    猜你喜欢
    • 2019-09-02
    • 2020-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-23
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多