【问题标题】:C++ block scope extern declaration linkage, confusing C++ standard explanationC++块作用域extern声明链接,混淆C++标准解释
【发布时间】:2018-12-28 21:16:26
【问题描述】:

标准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

块范围内声明的函数名和块范围内声明的变量名 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, 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,其中任何-std 值来自c++-11, c++-14, c++17。 什么基本支持 C++ 11 和 14 草案的措辞。 显然,这并没有更改为 c++17 值的编译错误。在这一点上,clang 不符合 C++ 17 吗?

【问题讨论】:

  • 不相关,但最好将 N3337 用于 C++11,将 N4141(或 N4140)用于 C++14。您使用的是中间草稿。
  • 对我来说,这个例子确实有意义:“块范围声明声明了相同的实体并接收前一个声明的链接”,这就是 #3 发生的情况。只有 C++ 17 的实现还没有符合新的变化,仍然按照以前的标准要求做。
  • @ShafikYaghmour 感谢您引用此问题。它是相关的,但是,它不是重复的。

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


【解决方案1】:

那是第 426 期:

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

[...] CWG 决定,最好让这种链接不匹配的程序格式不正确,而不是具有未定义的行为。

也就是说,如果一个名字有链接,它应该是一致的。实现可能还没有实现。

【讨论】:

  • 你对C++-11和C++-14的草案有什么看法,你觉得例子有错吗?
  • @Yuki 不,委员会修改了语言的实际规则。
  • 他们修改了 C++11 和 C++14 标准的最终版本?
  • @Yuki 不,他们将 C++17 的语言规则更改为不同于 C++14 中的语言规则。这两个例子都不正确,它们只是对应于不同的标准。
  • @Yuki 可见声明。然而,最外面的那个是不可见的。见eel.is/c++draft/basic.scope.hiding
猜你喜欢
  • 2022-01-13
  • 2010-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 2020-04-10
  • 2011-08-06
  • 1970-01-01
相关资源
最近更新 更多