转载于:http://blog.csdn.net/lincoln_2012/article/details/50801080

  项目中经常使用C和C++混合编程,那么,在调用对方接口时,总是不可避免地出现问题。为了让双方和谐地工作,就得用到extern "C"。

1 问题

在C++中,为了支持重载机制,在编译时,要对函数的名字进行一些处理,比如加入函数的返回类型等来加以区别;在C中,只是简单的函数名字而已。如函数void func(int i),C++会把它编译成类似_fun_int或_xxx_funIxxx这样的增加了参数类型的符号,这也是C++可以实现重载的原因;C则把该函数编译成类似_fun的符号,C链接器只要找到该函数符号就可以链接成功,它假设参数类型信息是正确的。故而,关键问题是,C和C++在编译时生成函数名字的方式是不同的。

2 方法

extern
"C"是C++的特性,是一种链接约定,它并不影响调用函数的定义,即使做了该声明,对函数类型的检查和参数转换仍要遵循C++的标准,而不是C。主要是为了解决C++在调用C函数库时,用C++直接链接就会出现不能识别符号的问题,而用上extern
"C"后,告诉C++编译器要以C语言的方式编译和链接函数,即直接使用函数名而不是一个经过处理的函数名。

3 示例

3.1 C++中调用C接口

代码:

  1. /***** C头文件c.h *****/
  2. #ifndef  _C_H_
  3. #define _C_H_
  4. #ifdef __cplusplus    /*C++编译器包含的宏,例如用g++编译时,该宏就存在,则下面的语句extern "C"才会被执行*/
  5. extern "C" {          /*C++编译器才能支持,C编译器不支持*/
  6. #endif
  7. void C_fun();
  8. #ifdef __cplusplus
  9. }
  10. #endif
  11. #endif
  1. /***** C源文件c.c *****/
  2. #include "c.h"
  3. void C_fun()
  4. {
  5. /*dosomething*/
  6. }
  1. 功能:在文件cpp.cpp中调用文件c.c中的函数C_fun()
  2. /****** C++源文件cpp.cpp ******/
  3. #include "c.h"
  4. int main()
  5. {
  6. C_fun()
  7. }

编译: g++ cpp.cpp c.c

3.2 C中调用C++接口

代码:

  1. /**** C++头文件 cpp.h *****/
  2. #ifndef  CPP_H
  3. #define CPP_H
  4. extern "C" int add( int x, int y );
  5. #endif
  1. /**** C++源文件 cpp.cpp *****/
  2. #include "cpp.h"
  3. int add( int x, int y )
  4. {
  5. return x + y;
  6. }
  1. 功能:C文件中调用C++的接口
  2. /**** C源文件c.c *****/
  3. extern int add( int x, int y );
  4. int main( int argc, char* argv[])
  5. {
  6. }

编译:gcc c.c cpp.cpp

3.3 C++中调用C库的函数

代码:

  1. /*C库源文件: hello.c*/
  2. #include <stdio.h>
  3. void func()
  4. {
  5. printf("hello,world!\n");
  6. }

编译:gcc --shared -o libhello.so hello.c

  1. /*C++源文件test.cpp中调用C库的函数*/
  2. #include <iostream>
  3. #ifdef __cplusplus
  4. extern "C" {               // 告诉编译器下列代码要以C链接约定的模式进行链接
  5. #endif
  6. void func();
  7. #ifdef __cplusplus
  8. }
  9. #endif
  10. int main()
  11. {
  12. func();
  13. return 0;
  14. }

编译:g++ test.cpp -o test -lhello

3.4 C中调用C++库的函数

1)C++库代码

  1. /*C++库源文件hello.cpp*/
  2. #include <iostream>
  3. void funcpp()
  4. {
  5. std::cout << "hello, world" << std::endl;
  6. }

编译:g++ --shared -o libhello.so hello.cpp
2)中间接口库,对C++库进行二次封装

  1. /*中间接口库 mid.cpp*/
  2. #include <iostream>
  3. void funcpp();
  4. #ifdef __cplusplus
  5. extern "C" {  // 即使这是一个C++程序,下列这个函数的实现也要以C约定的风格来搞!
  6. #endif
  7. void m_funcpp()
  8. {
  9. funcpp();
  10. }
  11. #ifdef __cplusplus
  12. }
  13. #endi

编译:g++ --shared -o libmid.so mid.cpp -lhello
3)C通过链接二次接口库调用C++库

  1. /*C源文件test.c*/
  2. #include <stdio.h>
  3. int main()
  4. {
  5. m_funcpp();
  6. return 0;
  7. }

编译:gcc test.c -l mid -o test

C与C++接口相互调用的更多相关文章

  1. 【c++基础】C与C++接口相互调用

    前言 编译程序的时候出现错误,入口程序如果是cpp文件可以编译成功,如果是c程序则出错.一般这个问题是c与c++之间接口相互调用出现的问题. 出现的错误是undefined reference to ...

  2. .Net 与 Java 的服务接口相互调用

    本文介绍.Net 与 Java 相互调用的例子.下面的介绍主要包括三方面:一是通过常用Web服务进行相互调用,二是使用TCP/IP套接字进行相互调用,三是使用Remote实现远程对象相互调用. 首先说 ...

  3. spring cloud各个微服务之间如何相互调用(Feign、Feign带token访问服务接口)

    1.首先先看什么是Feign. 这里引用“大漠知秋”的博文https://blog.csdn.net/wo18237095579/article/details/83343915 2.若其他服务的接口 ...

  4. WebView中Js与Android本地函数的相互调用

    介绍 随着Html5的普及,html在表现力上不一定比原生应用差,并且有很强的扩展兼容性,所以越来越多的应用是采用Html与Android原生混合开发模式实现. 既然要实现混合开发,那么Js与Andr ...

  5. JAVA和C/C++之间的相互调用。

    在一些Android应用的开发中,需要通过JNI和 Android NDK工具实现JAVA和C/C++之间的相互调用. Java Native Interface (JNI)标准是java平台的一部分 ...

  6. Android中通过WebView控件实现与JavaScript方法相互调用的地图应用

    在Android中通过WebView控件,可以实现要加载的页面与Android方法相互调用,我们要实现WebView中的addJavascriptInterface方法,这样html才能调用andro ...

  7. JAVA与.NET的相互调用——通过Web服务实现相互调用

    JAVA与.NET是现今世界竞争激烈的两大开发媒体,两者语言有很多相似的地方.而在很多大型的开发项目里面,往往需要使用两种语言进行集成开发.而很多的开发人员都会偏向于其中一种语言,在使用集成开发的时候 ...

  8. JAVA与.NET的相互调用——利用JNBridge桥接模式实现远程通讯

    分布式开发的历史 利用Remote方式调用远程对象实现服务器与客户端之间通讯是一种常用的网络开发方式,在.NET与JAVA开发当中,对Remote远程对象早已有着足够的支持(对Remote远程对象调用 ...

  9. android与javascript相互调用

    下面这一节来介绍android和javascript是怎么相互调用的,这样我们的UI界面设计起来就简单多了,而且UI设计起来也可以跨平台.现在有好多web app前台框架了,比如sencha和jque ...

随机推荐

  1. MongoDB 最初级步骤

    对库TEST下的LOG聚集集合中的inserttim字段加索引 步骤(注意:前四步步骤不能错,错了不行): 一,打开F:\mongodb\bin\mongo.exe,也可以用cmd命令指到这个exe执 ...

  2. express转发请求

    express var express = require('express'); var axios = require('axios'); var qs = require('qs'); var ...

  3. html的文档设置标记上(格式标记)4-5

    <html> <head> <title>第四课的标题及第五课的标题</title> <meta charset="utf-8" ...

  4. Kendo UI 单页面应用(三) View

    Kendo UI 单页面应用(三) View view 为屏幕上某个可视部分,可以处理用户事件. View 可以通过 HTML 创建或是通过 script 元素.缺省情况下 View 将其所包含的内容 ...

  5. GitHub 开启 Two-factor authentication,如何在命令行下更新和上传代码

    最近在使用GitHub管理代码,在git命令行管理代码时候遇到一些问题. 如果开起了二次验证(Two-factor authentication两个要素认证),命令行会一直提示输入用户名和密码.查找了 ...

  6. Selenium3+webdriver学习笔记3(xpath方式元素定位)

    #!/usr/bin/env python# -*- coding:utf-8 -*- from selenium import webdriver import time,os # about:ad ...

  7. winform ListView创建columnHeader的方法

    using System; using System.Windows.Forms; using System.Drawing; using System.Collections; namespace ...

  8. Linux下如何修改用户默认目录

      Linux下默认的用户目录一般为/home/xxx(root用户除外),有些时候我们可能需要修改这个目录,下面我就给大家分享2中修改的方法 工具/原料 Linux操作系统 方法/步骤 1 1.切换 ...

  9. 使用com.sun.imageio.plugins.png.PNGMetadata读取图片的元数据

    所谓图片元数据,就是除了我们肉眼看到的图片内容外,隐藏在这些内容背后的一些技术数据. 本文介绍如何使用Java代码将一张图片的隐藏信息读取出来. 首先不需要下载任何额外的Java库,用JDK自带的库就 ...

  10. 在.net平台上运行伪JAVA

    由于在一个项目局方要求使用JAVA平台, 而当前又都是.net平台的应用. 重新用JAVA开发工作量太大. 时间也来不及. 想到在.net中有url rewrite功能, 何不先"骗&quo ...