在内联函数中访问静态全局变量

Chr*_*odd 6 c++ gcc

我遇到了一个奇怪的问题,我缩小到以下测试用例:

inl.h:

inline const char *fn() { return id; }
Run Code Online (Sandbox Code Playgroud)

a.cc:

#include <stdio.h>

static const char *id = "This is A";

#include "inl.h"

void A()
{
    printf("In A we get: %s\n", fn());
}
Run Code Online (Sandbox Code Playgroud)

b.cc:

#include <stdio.h>

static const char *id = "This is B";

#include "inl.h"

void B()
{
    printf("In B we get: %s\n", fn());
}

extern void A();

int main()
{
    A();
    B();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在,当我编译它时g++ -O1 a.cc b.cc它似乎正常工作.我明白了:

In A we get: This is A
In B we get: This is B
Run Code Online (Sandbox Code Playgroud)

但如果我编译g++ -O0 a.cc b.cc我得到:

In A we get: This is A
In B we get: This is A
Run Code Online (Sandbox Code Playgroud)

请注意,我实际上是在尝试使用C11语义,但我使用的是g ++,因为gcc还不支持C11.

现在我可以看到,看看C11规范和C++规范(C++ 11和旧规范 - 内联和静态全局变量的语义似乎没有改变),它应该做我想要的,使用时失败-O0是gcc中的一个错误.

这是正确的,还是在我缺少的规范中某处会产生这种未定义的行为?

编辑

常见的答案似乎声称fn需要声明static为此起作用.但是根据C99规范的6.7.4.6(C11规范中的6.7.4.7 - 不确定C++规范):

如果转换单元中函数的所有文件范围声明都包含不带extern的内联函数说明符,则该转换单元中的定义是内联定义.内联定义不提供函数的外部定义,也不禁止另一个转换单元中的外部定义.

因为这里没有明确的extern,所以这些应该是两个独立的内联函数,彼此之间没有相互作用.不需要明确static.

使用显式静态修复了C的问题,但不适用于C++内联成员函数,因为static在这种情况下关键字具有完全不同的含义.

Rob*_*edy 8

你违反了单一定义规则.非静态函数fn在两个翻译单元中的定义不同.一个与a.cc中id定义的变量绑定,其中另一个与b.cc中的变量绑定.这些定义在文本上是相同的,但这还不足以满足单定义规则,即使为声明的函数设置了异常,因此您将获得未定义的行为.idinline

您使用的是C++编译器,而不是C编译器,因此C11所说的与C++程序所展示的行为无关.在C++ 11中,标准(§3.2/ 5)似乎说明了如何fn允许引用的规则id(强调和省略我的):

对于具有外部链接(7.1.2)的...内联函数,可以有多个定义...在程序中,每个定义出现在不同的翻译单元中,并且定义满足以下要求.鉴于这样的实体名称D在多个翻译单元中定义,那么

  • 每个定义D应由相同的令牌序列组成; 和
  • D根据3.4查找的相应名称的每个定义中,应在重载决议(13.3)之后和部分模板专门化匹配之后引用定义中定义的实体D,或引用同一实体(14.8.3) ),除非名称可以引用const 具有内部链接或没有链接的对象,如果该对象在所有定义中具有相同的文字类型D,并且该对象使用常量表达式(5.19)初始化,并且值(但不是地址) )使用对象,并且对象在所有定义具有相同的值D ; 和
  • ...

您的定义fn由相同的令牌序列组成,但它们指的id是未在其中定义的D,在两个翻译单元中不是同一个实体,并且在所有定义中没有相同的值.我认为C++标准中没有规定内联函数隐式获取内部链接.C++11§7.1.1/ 7说:

在没有存储类说明符的命名空间范围内声明的名称具有外部链接,除非由于之前的声明而具有内部链接,并且未声明它const.

如果你在某些优化级别或某些编译器的某些版本中获得了预期的行为,那么你只是得到了特定邪恶版本的未定义行为,即使是错误的事情似乎仍然有效.