当前位置: 技术问答>linux和unix
为什么同样的代码,链接同样的库,c成功链接,c++的会失败??
来源: 互联网 发布时间:2015-07-13
本文导语: 同样的程序,同样的路径配置. 用gcc编译链接正常.用g++编译能通过,链接时报错:找不到库函数. 程序非常简单,用到了oracle7的接口 int main() { Lda_Def lda; ocom(&lda); } 用g++编译时,编译可以通过(说明...
同样的程序,同样的路径配置.
用gcc编译链接正常.用g++编译能通过,链接时报错:找不到库函数.
程序非常简单,用到了oracle7的接口
int main()
{
Lda_Def lda;
ocom(&lda);
}
用g++编译时,编译可以通过(说明头文件里面找到了正确的ocom定义).
但链接不到(.so肯定是存在的,应该用gcc丝毫没有问题).
以我自己的理解,如果库函数的头文件里对c/c++区分,比如:
#ifdef C
ocom();
#endif
那么用g++编译时,#ifdef中的ocom定义会跳过,头文件中找不到正确的定义,
那么错误应该发生在编译这一步.
可是错误发生在链接.想不通阿.
g++链接时错误如下:
Undefined first referenced
symbol in file
ocom(cda_def*) /var/tmp//cc04hY6i.o
ld: fatal: Symbol referencing errors. No output written to a.out
用gcc编译链接正常.用g++编译能通过,链接时报错:找不到库函数.
程序非常简单,用到了oracle7的接口
int main()
{
Lda_Def lda;
ocom(&lda);
}
用g++编译时,编译可以通过(说明头文件里面找到了正确的ocom定义).
但链接不到(.so肯定是存在的,应该用gcc丝毫没有问题).
以我自己的理解,如果库函数的头文件里对c/c++区分,比如:
#ifdef C
ocom();
#endif
那么用g++编译时,#ifdef中的ocom定义会跳过,头文件中找不到正确的定义,
那么错误应该发生在编译这一步.
可是错误发生在链接.想不通阿.
g++链接时错误如下:
Undefined first referenced
symbol in file
ocom(cda_def*) /var/tmp//cc04hY6i.o
ld: fatal: Symbol referencing errors. No output written to a.out
|
c++的函数跟c函数看起来一样,但实际是不一样的,编译器会在C++函数名称里自动加上参数类型信息而C不会加,所以C程序去连接C++程序就会找不到这个函数。
extern "C" 就是告诉C++编译器,这个函数按照C的方式产生函数名称,这样就可以让C程序正确找到了。
extern "C" 就是告诉C++编译器,这个函数按照C的方式产生函数名称,这样就可以让C程序正确找到了。
|
C++与C生成的代码,命名方式是不同的。
比如你在C和C++下都定义了一个函数myfunc
那么C编译以后的函数名仍然是myfunc
但是C++编译以后的函数名是_7UXmyfunc(我只是举个例子,现实中可能前缀不是_7UX,反正有一串前缀)。它的作用主要是为了区别C++中的函数重载,因为可能有两个以上的myfunc函数,只是参数列表不同,而前边的前缀就是来区别函数列表的。
连接的时候,两种命名方式是不一样的,因此连接程序就无法连接了。
上边给你的建议,也不能对函数重载,否则不能以C的方式编译并连接了。
不知道你明白了没有。
比如你在C和C++下都定义了一个函数myfunc
那么C编译以后的函数名仍然是myfunc
但是C++编译以后的函数名是_7UXmyfunc(我只是举个例子,现实中可能前缀不是_7UX,反正有一串前缀)。它的作用主要是为了区别C++中的函数重载,因为可能有两个以上的myfunc函数,只是参数列表不同,而前边的前缀就是来区别函数列表的。
连接的时候,两种命名方式是不一样的,因此连接程序就无法连接了。
上边给你的建议,也不能对函数重载,否则不能以C的方式编译并连接了。
不知道你明白了没有。
|
(1)连接器报的错是给程序员看的,如果程序员对C++编译命名规则不清除,他就不会知道
哪个"_7uxfunc"是个什么东东, 所以应该报"func"
(2)你是加了extern "C"后才联接通过的吧?如果是这样,那问题好像又回到了你问题的出发点.
(3)这个问题不是很清除.但是如果c++要调用c的库时,肯定都应该加上extern "C".
哪个"_7uxfunc"是个什么东东, 所以应该报"func"
(2)你是加了extern "C"后才联接通过的吧?如果是这样,那问题好像又回到了你问题的出发点.
(3)这个问题不是很清除.但是如果c++要调用c的库时,肯定都应该加上extern "C".
|
C++对标识符名字做了mangle导致。mangle的方法没有标准,不同的编译器方法不同,所以CC和g++不能互相调用。
找Inside C++ OBject modle看看。
找Inside C++ OBject modle看看。
|
这个问题已经很清楚了吧.
这些都是编译器的问题,并不要去深究,
有空可以去看看lib,obj,PE,文件的格式,不同的操作系统,不同的加载器都会不同的
lippman 的 inside c++ object module,讲了一些编译器对C++语言的实现
打开那些二进制库文件看看
这些都是编译器的问题,并不要去深究,
有空可以去看看lib,obj,PE,文件的格式,不同的操作系统,不同的加载器都会不同的
lippman 的 inside c++ object module,讲了一些编译器对C++语言的实现
打开那些二进制库文件看看
|
c++里面调用c函数的时候,使用extern "C"告诉c++编译器要调用c函数了。
你可以看看stdio.h等这些ANSI头文件里面都用extern"C"来包含了函数 ,所以在c++里面调用这些函数的时候就不会出现连接错误,而你自己用c写的函数,如果头文件里面没有extern,在c++里面也没有extern,就会出现连接错误的问题,就是这个原因。
你可以看看stdio.h等这些ANSI头文件里面都用extern"C"来包含了函数 ,所以在c++里面调用这些函数的时候就不会出现连接错误,而你自己用c写的函数,如果头文件里面没有extern,在c++里面也没有extern,就会出现连接错误的问题,就是这个原因。