C++ 常量与非常量内联变量

C++ 常量与非常量内联变量,c++,c++17,inline,linkage,C++,C++17,Inline,Linkage,假设我有以下两个文件: test.cpp inline double pi { 3.1415 }; #include <iostream> void test() { std::cout << pi << std::endl; } inline默认情况下,变量具有外部链接。因此,我最初的想法是,根据一个定义规则(ODR),只要变量是内联声明的,并且包含相同的精确定义,就可以跨多个翻译单元声明相同的变量 所以我的第一个问题是,为什么这个程序要编译

假设我有以下两个文件:

test.cpp

inline double pi { 3.1415 };
#include <iostream>

void test() {

    std::cout << pi << std::endl;

}
inline
默认情况下,变量具有外部链接。因此,我最初的想法是,根据一个定义规则(ODR),只要变量是内联声明的,并且包含相同的精确定义,就可以跨多个翻译单元声明相同的变量

所以我的第一个问题是,为什么这个程序要编译,即使变量是内联声明的,它们在翻译单元中有不同的定义

第二,内联非常量和内联常量变量之间的区别是什么

例如,如果您运行上面的代码,您应该会得到以下输出

2.178
2.178

但是,如果您转到这两个文件并使
pi
a
constdouble
,即
inline constdouble pi{3.1415}
inline constdouble pi{2.178}

您将获得以下输出:

2.178
3.1415


这里到底发生了什么?

您的程序有未定义的行为,原因正是您给出的

您的工具链不需要诊断未定义的行为,而且,在通常很难“发现”的情况下(其中很多情况下),它甚至不会麻烦您。最好的情况是,链接器(而不是编译器)可以在构建过程中发现这个特殊情况,前提是编写它的人认为它足够有用,可以保证额外的工作和构建时间

但是,没有:这条规则属于程序员的责任范畴。你打破了规则,现在你的程序也被破坏了,以复杂的方式,我们可能可以利用足够的关于你的计算机、工具链、月相、情绪、鞋子颜色和程序组合的信息来解决这些问题……但这并没有任何价值


添加
const
可能会导致编译器(而不是链接器)在某些地方省略对该变量的“引用”,字面上是在使用点“内联”初始化器值,作为优化。当它知道值不会因初始化而改变时(由于
常量
),它可以这样做。其结果是,您不再从未定义的行为中观察到如此多的奇怪,因为您从程序中看到的行为更多地局限于单个翻译单元。

如果这些定义不同,您就违反了ODR。这就是UB。当你把一个内联变量放在一个标题中时,你认为会发生什么?链接器不会检查每个定义是否相同;它只会选择一个,并与它一起运行。至于你的第二个问题,如果一个变量是常量,而你从不尝试获取它的地址,那么不管它是否有外部链接,编译器都可以安全地内联它。@cigien编译器没有抱怨,这就是我感到困惑的原因。@MutatingAlgorithm没有什么可抱怨的。每个TU都很好。最多链接器可以诊断它。请每个问题一个问题。
inline double pi { 2.178 };

void test();

#include <iostream>

int main() {

    std::cout << pi << std::endl;
    test();

}