我一直在读一本有关编译器和链接器的书。该书提供了有关使用外部“ C”测试名称修饰的演示:
#include <stdio.h>
namespace myname{
int var = 42;
}
extern "C" double _ZN6myname3varE;
int main(){
printf("%d\n", _ZN6myname3varE);
return 0;
}
这本书说它将打印42,但是编译时出现错误。 使用:
g++ test_extern_c.cpp -o test_extern_c
并获得:
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 _ZN6myname3varE;
可以编译,结果为42。将代码extern "C" double _ZN6myname3varE;
移动到名称空间的顶部并更改类型:
#include <stdio.h>
extern "C" int _ZN6myname3varE;
namespace myname{
int var = 42;
}
//extern double _ZN6myname3varE;
int main(){
printf("%d\n", _ZN6myname3varE);
return 0;
}
结果也是42。
答案 0 :(得分:1)
请记住,名称修改是特定于工具的功能,并且不是C ++标准定义的。因此,并非所有C ++编译器都会为相同的声明生成相同的 mangled 名称。
但是,GNU编译器使用IA64 ABI规范进行名称修饰。从这个意义上讲,您的示例_ZN6myname3varE
是myname::var
的错误表示,但是类型是根据声明确定的,即,int
是myname::var
的前一个声明。并且编译器将后者视为对相同名称的重新声明,这是禁止的。
答案 1 :(得分:0)
这似乎可行:
#include <stdio.h>
namespace myname{
extern int var;
}
extern "C" int _ZN6myname3varE = 42;
int main(){
printf("%d\n", _ZN6myname3varE);
return 0;
}
尽管仍然有关于使用extern和initializng的投诉
答案 2 :(得分:0)
将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]#