C ++块作用域外部声明链接,使C ++标准解释混乱

时间:2018-07-20 14:18:15

标签: c++ clang c++14 language-lawyer c++17

标准N3242(C ++ 11草案)和N3797(C ++ 14草案)具有相同的段落。

  

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

     

¶6

     

在块作用域中声明的函数的名称和在块作用域extern中声明的变量的名称   申报有联系。如果存在具有相同名称的链接的实体的可见声明,并且   类型,忽略在最内层的封闭命名空间范围之外声明的实体,即块范围声明   声明同一实体,并接收先前声明的链接。如果不止一个这样的   匹配实体,则程序格式不正确。否则,如果找不到匹配的实体,则块作用域实体   接收外部链接。 [示例:

 static void f();
 static int i = 0; // #1
 void g() {
     extern void f(); // internal linkage
     int i; // #2 i has no linkage
     {
         extern void f(); // internal linkage
         extern int i; // #3 external linkage
     }
 }
     

三个名为i的对象   在这个程序中。具有内部链接的对象由   全局作用域(第1行)中的声明,具有自动存储期限且第2行中的声明未引入任何链接的对象   ,以及第3行中的声明引入的具有静态存储持续时间和外部链接的对象。   -结束示例   ]

我觉得i对象示例出了点问题,它不支持前面段落中的内容,对吗? 我认为它必须是两个i对象,一个具有内部链接(#1和#3),而一个没有链接(#2)。 我对么?是标准中的错误,示例是错误的吗?

相反,我认为标准N4659(C ++ 17草案)更正确地说明了这一点。

  

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

     

¶6

     

在块作用域中声明的函数的名称和在块作用域中声明的变量的名称   外部声明具有链接。如果存在具有相同名称的链接的实体的可见声明,并且   类型,忽略在最内层的封闭命名空间范围之外声明的实体,即块范围声明   声明同一实体,并接收先前声明的链接。如果不止一个这样的   匹配实体,则程序格式不正确。否则,如果找不到匹配的实体,则块作用域实体   接收外部链接。如果在翻译单元内使用内部和内部声明了相同的实体   外部链接,程序格式不正确。 [示例:

static void f();
static int i = 0; // #1
void g() {
    extern void f();
    // internal linkage
    int i; // #2: i has no linkage
    {
        extern void f(); // internal linkage
        extern int i; // #3: external linkage, ill-formed
    }
}
     

在第2行没有声明的情况下,在第3行的声明将与在第1行的声明链接。   由于具有内部链接的声明是隐藏的,因此,#3具有外部链接,这使得   程序格式错误。   -结束示例   ]

一些测试

static void f();
static int i = 10; // #1
void g() {
  extern void f(); // internal linkage
  std::cout << i << std::endl;
  int i = 2; // #2 i has no linkage
  std::cout << i << std::endl;
  {
    extern void f(); // internal linkage
    std::cout << i << std::endl;
    extern int i; // #3 external linkage
    std::cout << i << std::endl;
  }
}

int main() {
  g();
  return 0;
}

此代码在clang-5.0中使用来自10 2 2 10的{​​{1}}值生成-std。 基本上支持C ++ 11和14草案措辞的内容。 显然,这并没有变为具有c++-11, c++-14, c++17值的编译错误。此时clang是否不符合C ++ 17?

1 个答案:

答案 0 :(得分:5)

那是问题426:

  

这真的是我们想要的吗? C99具有6.2.2.7/7,它提供了未定义的行为,使标识符与内部和外部链接出现在同一翻译单元中。 C ++似乎没有它。

     

[…] CWG决定,将程序设计成具有这种形式的链接失配,而不是具有不确定的行为。

也就是说,决定一个名称具有链接,则该名称应保持一致。实现可能尚未实现。