代码之家  ›  专栏  ›  技术社区  ›  Yuki

C++块范围外声明链接,混淆C++标准解释

  •  8
  • Yuki  · 技术社区  · 6 年前

    标准 N3242 (C++ 11草案) N3797 (C++ 14草案)都有同一段落。

    §3.5程序和链接[基本链接]

    块作用域中声明的函数名和块作用域外部声明的变量名 声明具有链接。如果存在具有相同名称和 类型,忽略在最内部封闭命名空间范围外声明的实体,块范围声明 声明同一实体并接收上一声明的链接。如果有不止一个这样的 匹配实体时,程序格式错误。否则,如果找不到匹配的实体,则块范围实体 接收外部链接。[示例:

     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
         }
     }
    

    有三个物体叫我 在这个程序中。由 全局范围内的声明(行1),由行2上的声明引入的具有自动存储持续时间且没有链接的对象。 以及由第3行声明引入的具有静态存储持续时间和外部链接的对象。 结束示例 ]

    我觉得有点问题 i 对象示例,它不支持前面段落中所说的内容,对吗? 我认为一定是两个 对象,一个具有内部链接(1和3),另一个不具有链接(2)。 我说的对吗?这是标准中的错误吗?这个例子是错误的?

    相比之下,标准 N4659 (C++ 17草案)在我看来更正确。

    §6.5程序和链接[基本链接]

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

    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;
    }
    

    此代码生成 10 2 2 10 在Clang-5.0中 -std 值来自 c++-11, c++-14, c++17 . 基本上支持C++ 11和14草稿的措辞。 显然,这并没有变为编译错误 c++17 值。CLAN在这一点上不符合C++ 17吗?

    1 回复  |  直到 6 年前
        1
  •  5
  •   Columbo    6 年前

    这是第426期:

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

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

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