C++ 使用extern时,类型与以前的外部decl不匹配;";
我一直在读一本关于编译器和链接器的书。这本书给出了一个关于使用外部“C”测试名称混乱的演示: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:
#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的结果。好吧,扔掉这本书:/这不是一个重新声明,它是一个外部声明,一个前瞻性声明。转发声明非常好。@MatthieuBrucherextern“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]#