Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用extern时,类型与以前的外部decl不匹配;";_C++_Linux - Fatal编程技术网

C++ 使用extern时,类型与以前的外部decl不匹配;";

C++ 使用extern时,类型与以前的外部decl不匹配;";,c++,linux,C++,Linux,我一直在读一本关于编译器和链接器的书。这本书给出了一个关于使用外部“C”测试名称混乱的演示: #include <stdio.h> namespace myname{ int var = 42; } extern "C" double _ZN6myname3varE; int main(){ printf("%d\n", _ZN6myname3varE); return 0; } 并获得: test_extern_c.cpp:15:19: error:

我一直在读一本关于编译器和链接器的书。这本书给出了一个关于使用外部“C”测试名称混乱的演示:

#include <stdio.h>

namespace myname{
    int var = 42;
}

extern "C" double _ZN6myname3varE;

int main(){
    printf("%d\n", _ZN6myname3varE);
    return 0;
}
并获得:

test_extern_c.cpp:15:19: error: type mismatch with previous external decl of ‘double _ZN6myname3varE’ [-fpermissive]
 extern "C" double _ZN6myname3varE;
                   ^
test_extern_c.cpp:12:9: note: previous external decl of ‘int myname::var’
     int var = 42;
         ^
test_extern_c.cpp:15:19: error: redeclaration of ‘double _ZN6myname3varE’
 extern "C" double _ZN6myname3varE;
                   ^
test_extern_c.cpp:12:9: note: previous declaration ‘int myname::var’
     int var = 42;
所以我想知道会发生什么。我还将_ZN6myname3varE的类型更改为int。它将给出编译器错误:

test_extern_c.cpp:15:16: error: redeclaration of ‘int _ZN6myname3varE’
 extern "C" int _ZN6myname3varE;
                ^
test_extern_c.cpp:12:9: note: previous declaration ‘int myname::var’
     int var = 42;
我的环境和这本书的环境有什么不同吗?或者不同版本的g++可能有不同的规则

我做了一些探索:

  • 删除代码
    extern“C”double\u ZN6myname3varE
    它可以被编译,结果是42
  • 移动代码
    extern“C”double\u ZN6myname3varE到命名空间顶部并更改类型:

    #include <stdio.h>
    
    extern "C" int _ZN6myname3varE; 
    
    namespace myname{
        int var = 42;
    }
    
    //extern double _ZN6myname3varE;
    
    int main(){
        printf("%d\n", _ZN6myname3varE);
        return 0;
    }
    
    #包括
    外部“C”int_ZN6myname3varE;
    名称空间myname{
    int-var=42;
    }
    //外双锌合金;
    int main(){
    printf(“%d\n”,ZN6myname3varE);
    返回0;
    }
    
  • 结果为42。

    请记住,名称的模糊是一个工具的特定特征,不是由C++标准定义的。因此,不是所有C++编译器都会为同一声明生成相同的已损坏名称。 然而,GNU编译器使用该规范进行名称篡改。从这个意义上讲,您的示例

    \u ZN6myname3varE
    myname::var
    的一个损坏的表示形式,但是类型是根据声明确定的,即
    myname::var
    的前一个声明的
    int
    。编译器将后者视为同名的重新声明,这是禁止的。

    这似乎有效:

    #include <stdio.h>
    
    namespace myname{
            extern int var;
    }
    
    extern "C" int _ZN6myname3varE = 42;
    
    int main(){
            printf("%d\n", _ZN6myname3varE);
                return 0;
    }
    
    #包括
    名称空间myname{
    外部变量;
    }
    外部“C”int_ZN6myname3varE=42;
    int main(){
    printf(“%d\n”,ZN6myname3varE);
    返回0;
    }
    

    尽管仍有人抱怨使用extern和初始化将double改为int,但它可以工作

    [root@centos-test tmp]# cat t.cc
    #include <stdio.h>
    
    namespace myname{
        int var = 42;
    }
    
    extern "C" int _ZN6myname3varE;
    
    int main(){
        printf("%d\n", _ZN6myname3varE);
        return 0;
    }
    [root@centos-test tmp]# ./t
    42
    [root@centos-test tmp]# 
    
    [root@centos-测试tmp]#cat t.cc
    #包括
    名称空间myname{
    int-var=42;
    }
    外部“C”int_ZN6myname3varE;
    int main(){
    printf(“%d\n”,ZN6myname3varE);
    返回0;
    }
    [root@centos-测试tmp]#/t
    42
    [root@centos-测试tmp]#
    
    \u ZN6myname3varE
    是一个保留标识符。我很确定你的代码有未定义的行为。非常糟糕的东西。如果要将代码外部化,请不要使用名称空间,也不要使用类。什么书?这本书的演示想要测试gcc编译器中的名称修饰。符号_ZN6myname3varE是名称空间myname中变量的函数签名@melpomene@MatthieuBrucher这是一本中文书,我删除了代码行:extern“C”double\u ZN6myname3varE;我得到了42的结果。好吧,扔掉这本书:/这不是一个重新声明,它是一个外部声明,一个前瞻性声明。转发声明非常好。@MatthieuBrucher
    extern“C”
    与简单的
    extern
    有很大不同。你可以看到这个了解更多信息。你使用什么cpmpiler?GCC?我尝试在我的计算机上使用GCC,但出现了一个错误。错误:“int”的重新声明。原因可能是var的符号是“u ZN6myname3varE” 在gcc标准中。@windyear g++4.8.5我尝试了这个方法,但仍然出现错误。这意味着重新声明了“int\u ZN6myname3varE”。符号_ZN6myname3varE是名称空间中var的名称修饰,因此它是一个重新声明。另外,我使用gcc编译器,其他编译器也可以工作。
    [root@centos-test tmp]# cat t.cc
    #include <stdio.h>
    
    namespace myname{
        int var = 42;
    }
    
    extern "C" int _ZN6myname3varE;
    
    int main(){
        printf("%d\n", _ZN6myname3varE);
        return 0;
    }
    [root@centos-test tmp]# ./t
    42
    [root@centos-test tmp]#