Chinaunix首页 | 论坛 | 博客
  • 博客访问: 6267045
  • 博文数量: 2759
  • 博客积分: 1021
  • 博客等级: 中士
  • 技术积分: 4091
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-11 14:14
文章分类

全部博文(2759)

文章存档

2019年(1)

2017年(84)

2016年(196)

2015年(204)

2014年(636)

2013年(1176)

2012年(463)

分类: C/C++

2014-04-30 12:24:34

原文地址:C 和 C++ 混合编程 (2) 作者:xuebabybaby

            在最近的arm开发中,因为一些特定的需求,需要使用从C文件中调用以前C++程序中的类和方法。参考网上的一些资料,本文1将相关的知识点简要总结如下:c&c++混合编程的注意事项,在c++函数中调用c函数的方法,在c函数中调用c++函数的方法,在c函数中调用C++对象及其中数据的方法。并在本文的末尾给出C和C++混合编程的例子,例子分别以Makefile和VC6.0工程的形式展现。

注意事项

本部分是从较高的角度需要注意的问题:
C和C++编译器必须要兼容
C和C++编译器要有兼容的头文件和运行库

建议使用同一个供货商的编译器:即如果使用的gnu,那么C编译器是gcc,C++编译器是g++。

如何在C++代码中包含标准C头文件?


包含一个标准的头文件(如),不需要任何特别的处理。

点击(此处)折叠或打开

  1. // c++ 代码
  2. #include <cstdio> // 头文件包含没啥特别处理
  3. int main()
  4. {
  5.     std::printf("Hello world\n");// 函数调用没啥特别处理
  6.     return 0;
  7. }

如果,你认为std::printf中的std::很奇怪,那么最好的方式就是“习惯它”。换句话说,这是使用标准库函数的标准方法,所以习惯这种用法就好了。

但是,如果你想要使用C++编译器来编译C代码的话,就不用使用这么奇怪的std::printf()了。这种情况下,你需要包含,而不是,神奇的命名空间会替你解决所有事情。代码如下:
 

点击(此处)折叠或打开

  1. //使用C++编译器编译的C代码
  2. #include <stdio.h> // 头文件包含没啥特别处理
  3. int main()
  4. {
  5.     printf("Hello world\n");// 函数调用没啥特别处理
  6.     return 0;
  7. }


补充:如果使用非标准库的头文件的话,关注点会有所改变,非标准库的使用有以下两种情况:不能修改头文件和能够修改头文件。

如何在C++代码中包含非系统C头文件?

如果在C++系统中使用一个非系统提供的c头文件时,需要将#include代码用extern “C”{}包含起来,这个声明告诉C++编译器,包含在内的是C函数的头文件。
 

点击(此处)折叠或打开

  1. //C++ 代码

  2. extern "C" {
  3. //get declaration for f(int i, char c, float x)
  4. #include "my-c-code.h"
  5. }

  6. int main()
  7. {
  8.     f(7, 'x', 3.14); //正常调用
  9. }


补充:可能出现的不同情况系统提供的标准头文件(比如)和能够修改头文件。

 如何修改C头文件,以使之方便的被C++代码#incldue?

如果需要包含一个非系统的C头文件,同时,你拥有修改此文件的权限,那么强烈建议在文件的内部加上extern “C” {…},以使用C++程序员能够方便的使用。当然,作为C编译器,是不理解什么叫extern “C”的,因此,需要将extern “C”使用#ifdef包起来。
    第一步:在C头文件的最顶端加上如下代码(__cplusplus只存在于C++编译器下)
 

点击(此处)折叠或打开

  1. #ifdef __cplusplus
  2. extern "C" {
  3. #endif

    第二步:在C头文件的最尾部加入如下代码


点击(此处)折叠或打开

  1. #ifdef __cplusplus
  2. }
  3. #endif



现在,就可以在C++代码中使用C头文件,而不用使用任何蹩脚的extern “C” {}
 

点击(此处)折叠或打开

  1. // this is c++ code
  2. //get the declaration of f(int i, char c, float x)
  3. #include "my-c-mode.h"
  4. int main()
  5. {
  6.     f(7, 'x', 3.14); //正常调用
  7. }
补充:可能出现的不同情况系统提供的标准头文件(比如)和不能修改头文件。


如何在C++代码中调用非标准的C函数?

现在也许你有一个单独的C函数,但是呢,出于某种原因,你并想包含声明此函数的头文件。那么你可以在C++代码中声明此单独的函数,代用extern “C” 的语法。你应该如下方式使用:

点击(此处)折叠或打开

  1. extern "C" void f(int i, char c, float x)

如果是许多程序的话,可以用大括号包含:
 

点击(此处)折叠或打开

  1. extern "C" {
  2.     void f(int i, char c, float x);
  3.     int g(char* s, char const* s2);
  4.     double sqrtOfSumOfSquares(double a, double b);

  5. }


经此声明,在C++函数中调用这些C函数就变的很简单:
 
  1. int main()
  2. {
  3.     f(7, 'x', 3.14); // Note: nothing unusual in the call
  4. }

如何写出能够被C代码中调用的C++函数?

当知道一个C++函数会被C编译器调用时,可以使用extern “C” 结构来声明函数。
 
    1. //c++ code
    2. //声明
    3. extern "C" f(int, char, float);

    4. //....
    5.  
    6. //在某个C++模块中定义此函数
    7. void f(int i, char c, float x)
    8. {
    9. //.....
    10. }

extern “C” 这行告诉C++编译器,当有external信息在链接时,使用C调用规范和函数命名方式。

另:因为C并不支持重载,所以不能够实现用C调用重载函数。

C/C++混合编程时,出现linker错误

如果,函数没有正确的设置了extern “C”,那么有可能出现链接错误而不是编译错误。这是因为C++编译器经常会”mangle”函数名(做特殊处理)– 一种于C编译器不同的方式。

如何将一个C++类的对象传给一个C函数

 例子: Fred.h:

点击(此处)折叠或打开

  1. //此头文件C/C++编译器都访问
  2. /* This header can be read by both C and C++ compilers */
  3. #ifndef FRED_H
  4. #define FRED_H

  5. #ifdef __cplusplus
  6. class Fred {
  7.     public:
  8.         Fred();
  9.         void wilma(int);
  10.     private:
  11.         int a_;
  12. };
  13. #else
  14.     typedef
  15.         struct Fred
  16.         Fred;
  17. #endif

  18. #ifdef __cplusplus
  19. extern "C" {
  20. #endif

  21. #if defined(__STDC__) || defined(__cplusplus)
  22.     extern void c_function(Fred*); /* ANSI C prototypes */
  23.     extern Fred* cplusplus_callback_function(Fred*);
  24. #else
  25.     extern void c_function(); /* K&R style */
  26.     extern Fred* cplusplus_callback_function();
  27. #endif

  28.  #ifdef __surplus
  29. }
  30. #endif

  31. #endif /*FRED_H*/

Fred.cpp:
 

点击(此处)折叠或打开

  1. // This is C++ code

  2. #include "Fred.h"

  3. int main()
  4. {
  5.     Fred fred;
  6.     c_function(&fred);
  7. ...
  8. }


c-function.c
 

点击(此处)折叠或打开

  1. /* This is C code */

  2. #include "Fred.h"

  3. void c_function(Fred* fred)
  4. {
  5.     cplusplus_callback_function(fred);
  6. }


c代码不能像c++代码一样,能够分辨出两个指针指向的是同一个对象,除非两个指针是严格的同一个类型。

举个例子,假设有两个对象,Derived* dp,和Base* bp,下面语句if(dp == bp)在c++下正常,c++编译器会自动将两个指针转为同一个类型,在这个例子中,两个指针都给转换成Base*,然后比较。这个过程,C做不到。

显而易见:C编译器不知道如何做种指针转换,所以如果非要对比这两个指针的话,Derived*到Base*的转换应该在C++编译器的地方完成,而不要C编译器做做这个工作。

 C函数能够直接访问C++类的数据吗?

看情况。

在以下情况下,C函数能够直接访问C++对象的数据成员:
没有虚函数(也不能用继承的虚函数)
所以的数据在同一个访问层次(private/protected/public)
不包含有虚函数的子对象如果C++类有任意基类(或者是包含基类的子对象),直接认为data在技术上来说,都是不可移植的,因为继承层次下的类的数据的布局不是硬性规定的,所以每个编译器可能会有所不同。想深入了解虚函数相关的实现技术可参考<深入探索C++对象模型>2

链接程序+例子

展示本文用法的例子及使用linux时的链接方法,本例子有Makefile和VC6.0工程两种组织方式:下载地址

自:还有注意上面的用法中
有在extern "C" extern  int extern void c_function(Fred*);  //就是在CPP的情况下,声明时有两个extern词语


Time-stamp: 2010-12-22 21:48:49 fangzhzh
Footnotes:

1

2

转: http://blog.csdn.net/liang890319/article/details/7287592
阅读(1155) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~