C++调用C语言的库函数
在项目中,使用C语言编写了一个socket后台程序tkcofferd,并且为方便客户端的使用,提供了动态库,其中包含socket接口。
现在的需求是使用qt做一个前端界面,用来展示tkcofferd的socket接口功能,用于测试目的。
qt中使用c++语言编写,如果需要调用tkcofferd的socket接口(由C语言编写),需要指明函数导出方式,详述如下:
转自http://linhs.blog.51cto.com/370259/140927
C++调用C的库函数时,如果头文件定义得不恰当,可能会出现明明某函数在obj文件中存在,但是却发生链接失败的情况,出现如下错误:
undefined reference to 'xxx'
出现问题的原因是c库函数编译成obj文件时对函数符号的处理和C++不同。因为C++函数支持重载,所以函数符号的处理要更复杂一些,c往往不作修饰。
例如有函数:
/* dofunc.c */ #include <stdio.h>
int dofunc()
{
printf("dofunc\n");
}
使用gcc编译成obj后
#生成 dofunc.o
objdump -x dofunc.o
[0](sec -2)(fl 0x00)(ty 0)(scl 103) (nx 1) 0x00000000 dofunc.c
File
[2](sec 1)(fl 0x00)(ty 20)(scl 2) (nx 1) 0x00000000 _dofunc
AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0
[4](sec 1)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .text
AUX scnlen 0x14 nreloc 2 nlnno 0
[6](sec 2)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .data
AUX scnlen 0x0 nreloc 0 nlnno 0
[8](sec 3)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .bss
AUX scnlen 0x0 nreloc 0 nlnno 0
[10](sec 4)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .rdata
AUX scnlen 0x8 nreloc 0 nlnno 0
[12](sec 0)(fl 0x00)(ty 20)(scl 2) (nx 0) 0x00000000 _printf
再看看使用g++编译后的代码:
g++ -c dofunc.c
SYMBOL TABLE:
[ 0](sec -2)(fl 0x00)(ty 0)(scl 103) (nx 1) 0x00000000 dofunc.c
File
[ 2](sec 1)(fl 0x00)(ty 20)(scl 2) (nx 1) 0x00000000 __Z6dofuncv
AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0
[ 4](sec 1)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .text
AUX scnlen 0x14 nreloc 2 nlnno 0
[ 6](sec 2)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .data
AUX scnlen 0x0 nreloc 0 nlnno 0
[ 8](sec 3)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .bss
AUX scnlen 0x0 nreloc 0 nlnno 0
[ 10](sec 4)(fl 0x00)(ty 0)(scl 3) (nx 1) 0x00000000 .rdata
AUX scnlen 0x8 nreloc 0 nlnno 0
[ 12](sec 0)(fl 0x00)(ty 20)(scl 2) (nx 0) 0x00000000 _printf
g++编译后的函数符号名比较古怪:__Z6dofuncv
可见C和C++在加工函数名方面是很大不同的。
如果有C++程序要使用dofunc.o ,如下程序的函数声明是错的
// main_dev.cpp int dofunc(); int main(int argc , char* args[])
{
dofunc();
system("pause");
}
g++ -o main_dev main_dev.cpp dofunc.o
main_dev.cpp: undefined reference to `dofunc()'
collect2: ld returned 1 exit status
原因是dofunc函数在加工后函数名应该为__Z6dofuncv ,dofunc.o文件里面的是_dofunc,所以找不到。
如果有dofunc的源代码,解决办法很简单,将dofunc.c使用c++来编译即可。
如果不幸地dofunc函数在别人的库里面,而这个库是用c编写和gcc编译的,源代码不可见,那怎么办呢?
幸亏C++和编译器的设计者早已料到了这个问题,并提供了一种通用的解决办法:使用extern "C"来修饰旧C库的外部函数声明。
extern "C" {
int dofunc();
} int main(int argc , char* args[])
{
dofunc();
system("pause");
}
g++ -o main_dev main_dev.cpp dofunc.o
成功
extern "C"修饰内的函数,一律按照c的风格来编译,以便能够链接到用c编译出来的obj库上去。
常见有形如:
#ifdef __cplusplus
extern "C" {
#endif
int dofunc();
#ifdef __cplusplus
}
#endif
这种的头文件一般是库开发者提供的,能同时被c和c++模块使用。宏__cplusplus 是c++编译器定义的,这种写法保证了用C++编译时extern "C" 能生效;而用c编译时又不会因不会处理extern "C"而错误。
反过来,如果c需要调用C++编译的库又怎么办呢?相信一般情况下不会有这样奇特的要求,直接用C++编译不就完了?
把main_dev.cpp改名为main.c ,然后
gcc -o main_dev main_dev.c dofunc.o
当然会出现: undefined reference to `dofunc'
因为fofunc.o里面的符号是__Z6dofuncv ,所以链接会失败,只能有一种非常恶心的方法去链到那个函数:
//main_dev.c
int (*dofunc)(); /* 声明函数指针 */
int _Z6dofuncv(); /* 会链接到 __Z6dofuncv */ int main(int argc , char* args[])
{
dofunc=_Z6dofuncv; /* 函数指针赋值 */
dofunc();
system("pause");
}
gcc -o main_dev main_dev.c dofunc.o
成功
上面讲了那么多,中心意思都是c和c++编译和链接时对函数名加工的细节问题,理解了这些细节后,如何运用完全就存乎一心了。
C++调用C语言的库函数的更多相关文章
- 通过调用C语言的库函数与在C代码中使用内联汇编两种方式来使用同一个系统调用来分析系统调用的工作机制
通过调用C语言的库函数与在C代码中使用内联汇编两种方式来使用同一个系统调用来分析系统调用的工作机制 前言说明 本篇为网易云课堂Linux内核分析课程的第四周作业,我将通过调用C语言的库函数与在C代码中 ...
- .Net调用R语言
///加载自己写的R语言算法库 public List<double> GetZTFB(double[] data) { List<double> par = new List ...
- 分享:写了一个 java 调用 C语言 开发的动态库的范例
分享:写了一个 java 调用 C语言 开发的动态库的范例 cfunction.h 代码#pragma once#ifdef __cplusplusextern "C" {#e ...
- JAVA调用C语言写的SO文件
JAVA调用C语言写的SO文件 因为工作需要写一份SO文件,作为手机硬件IC读卡和APK交互的桥梁,也就是中间件,看了网上有说到JNI接口技术实现,这里转载了一个实例 // 用JNI实现 // 实例: ...
- Java JNI调用c语言的dll测试
最近复习C语言和java语言(10年没用了,温习一下),用JNI调用C语言的dll测试,以前没做过,在网上找了很多,总结如下: 环境:windows 10(64位) + JDK(32位,版本1.7.0 ...
- keil or c51 汇编调用c语言函数 容易忽视的问题
最近,在用keil 写一个小程序时,想实践一下从汇编调用 C语言函数,我们都知道C语言调用汇编函数讨论得较多,但反过来,从汇编中调用C语言的函数未见深入分析:在开始的时候,还是忽视了一个问题,就是对现 ...
- lua调用C语言
在上一篇文章(C调用lua函数)中,讲述了如何用c语言调用lua函数,通常,A语言能调用B语言,反过来也是成立的.正如Java 与c语言之间使用JNI来互调,Lua与C也可以互调. 当lua调用c ...
- Java 拓展之调用其他语言
目前而言,编程语言真的是太多了.每一种都是一种智慧的结晶,但是每个都存在其缺点.网上经常能看到一些程序员争论"XX是世界上最好的语言"之类的话题.其实我们大可不必这样.语言本身只是 ...
- .net 调用R语言的函数(计算统计值pvalue 对应excel :ttest)
Pvalue 计算 项目设计pvalue计算,但是由于.net 没有类似的公式或者函数,最终决定使用.net 调用R语言 采用.net 调用r语言的公用函数 需要安装 r语言环境 https://mi ...
随机推荐
- MySQL学习笔记(四)悲观锁与乐观锁
恼骚 最近在搞并发的问题,订单的异步通知和主动查询会存在并发的问题,用到了Mysql数据库的 for update 锁 在TP5直接通过lock(true),用于数据库的锁机制 Db::name('p ...
- [再寄小读者之数学篇](2014-06-26 Logarithmical Sobolev inequality using BMO space)
$$\bex q>3\ra \sen{\n f}_{L^\infty} \leq C(q)\sez{ 1+\sen{\n f}_{BMO} \ln^\frac{1}{2}\sex{e+\sen{ ...
- Pytorch中的自动求导函数backward()所需参数含义
摘要:一个神经网络有N个样本,经过这个网络把N个样本分为M类,那么此时backward参数的维度应该是[N X M] 正常来说backward()函数是要传入参数的,一直没弄明白backward需要传 ...
- 大家都知道fastclick能解决300ms延迟,现在我们来看一下,使用方法
1.在终端输入以下命令进行安装 npm install fastclick -S 2.在你用脚手架搭建好的项目中,找到mian.js这个入口文件,打开 3.在其中加入: import FastClic ...
- Vue技术内幕 出去看看吧 实例化+挂载
实例化时挂载DOM 从 Vue.prototype.$mount 挂载函数开始 有 template配置项时生成 render函数
- day 14 - 2 生成器练习
相关练习 1.处理文件,用户指定要查找的文件和内容,将文件中包含要查找内容的每一行都输出到屏幕 #比较 low 的方法 def check_file(filename,aim): with open( ...
- C语言之路-3-循环
1.while循环计算数字位数 #include<stdio.h> int main() { ; int x; printf("请输入数字:"); scanf(&quo ...
- sql server的sysobjects表中xtype字段值的含义
xtype字段包含的值的意思如下: AF = Aggregate function (CLR) 聚合函数(CLR) C = CHECK constraint CHECK约束 D = Default ...
- 第一章 Bootstrap简介
一.Bootstrap简介 Bootstrap是基于 HTML.CSS.JAVASCRIPT 的前端框架,它简洁灵活,使得 Web 开发更加快捷.它由Twitter的设计师Mark Otto和Jaco ...
- Misc杂项隐写题writeup
MISC-1 提示:if you want to find the flag, this hint may be useful: the text files within each zip cons ...