使用外部字符“ C”时,类型与先前的外部decl不匹配

时间:2018-12-08 08:20:43

标签: c++ linux

我一直在读一本有关编译器和链接器的书。该书提供了有关使用外部“ 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 ++版本具有不同的规则?

我有一些探险家:

  1. 删除代码extern "C" double _ZN6myname3varE; 可以编译,结果为42。
  2. 将代码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。

3 个答案:

答案 0 :(得分:1)

请记住,名称修改是特定于工具的功能,并且不是C ++标准定义的。因此,并非所有C ++编译器都会为相同的声明生成相同的 mangled 名称。

但是,GNU编译器使用IA64 ABI规范进行名称修饰。从这个意义上讲,您的示例_ZN6myname3varEmyname::var的错误表示,但是类型是根据声明确定的,即,intmyname::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]#