C与C++混编所遇到的问题

今天团队成员做了一个PID算法,是用C语言实现的。而我的图像处理算法依赖于opencv库,使用的C++,要在C++中嵌入C语言,一般的函数g++是兼容的,但是队友用了信号的方式进行进程控制,按照一般方式编译总是会出现如下的错误:

error: invalid conversion from 'void (*)()' to '__sighandler_t {aka void (*)(int)}' [-fpermissive]
从错误的字面意思判断,初始化信号的时候,安装处理函数时,不能正常初始化,格式上是不被容许的。

把PID处理的C程序编译一遍,没有错。使用g++进行编译会一直出现这样的错误~网上google一下,有人说是缺少“time.h”头文件,我查找了下并没有缺少。突然想到,我使用的是C与C++混编,是不是编译器处理的时候造成格式不同的原因,才会造成这个错误!后面确认确实是这个错误!下面我将处理的过程描述一遍。

说到C与C++混编,不得不提一下extern “C”,这个是最常用的,它有什么作用呢?其作用有以下几点:

1. extern "C"的真实目的是实现类C和C++的混合编程。extern “C”是由C++提供的一个连接交换指定符号,用于告诉C++这段代码是C函数。extern “C”后面的函数不使用的C++的名字修饰,而是用C。这是因为C++编译后库中函数名会变得很长,与C生成的不一致,造成C++不能直接调用C函数。

2.C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为:void foo(int x, int y);该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。C++提供了C连接交换指定符号extern“C”来解决名字匹配问题。

3.被extern "C"限定的函数或变量是extern类型的;extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。被extern "C"修饰的变量和函数是按照C语言方式编译和连接的。

4.与extern对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。

下面看一道腾讯的面试题,解释下面的代码:

	#ifndef  BAT_INCLUDE
 	#define    BAT_INCLUDED
	  
 	#ifdef __cplusplus
 	extern "C" {
 	#endif /* __cplusplus */
 	  
 	/*.................................
 	 * do something here
 	 *.................................
 	 */ 	  
 	#ifdef __cplusplus
 	}
 	#endif /* __cplusplus */
     #endif /* BAT_INCLUDED */
首先,我们来理解下 #ifndef #endif 的作用?这个表达的是条件编译。为了解释一个问题,我假设这些内容包含于bat.h中, bat.h可能在项目中被多个源文件包含(#include "bat.h"),而对于一个大型项目来说,这些冗余可能导致错误,因为一个头文件包含类定义或inline函数,在一个源文件中bat.h可能会被#include两次(如,alibaba.h头文件包含了bat.h,而在baidu.c文件中#include alibaba.h和bat.h)——这就会出错(在同一个源文件中一个结构体、类等被定义了两次)。 从逻辑观点和减少编译时间上,都要求去除这些冗余。然而让程序员去分析和去掉这些冗余,不仅枯燥且不太实际,最重要的是有时候又需要这种冗余来保证各个模块的独立 为了解决这个问题,上面代码中的

#ifndef BAT_INCLUDED
#define    BAT_INCLUDED
/*……………………………*/
#endif /* BAT_INCLUDED */

就起作用了。如果定义了BAT_INCLUDED,#ifndef  #endif之间的内容就被忽略掉。因此,编译时第一次看到BAT.h头文件,它的内容会被读取且给定BAT_INCLUDED一个值。之后再次看到bat.h头文件时,BAT_INCLUDED就已经定义了,BAT.h的内容就不会再次被读取了。

下面解释:

#ifdef __cplusplus
       extern "C" {
       #endif
       #ifdef __cplusplus
       }
       #endif
_cplusplus标示符用来判断程序是用c还是c++编译程序编译的。当编译c++程序时,这个标示符会被定义,编译c程序时,不会定义。于C++文档的头文件中,上面代码的意思是:如果是C++文件(*.cpp)后缀,则使用extern “C”,在C++项目中经常见到。

接下来处理今天遇到的问题,C++中如何调用C程序。看下面一个简单的例子:

1、hello.h中输入:

#ifndef  HELLO_H
#define  HELLO_H
#include 
extern void print(char* );
#endif
2、hello.c中输入:

#include "hello.h"
void print(char* data)
{
     printf("%s\n", data);
}
3、main.cpp中输入:

extern "C"{
#include "hello.h"
}
int main(void)
{
print(“hello,world\n”);
return 0;
}
编写makefile文件:

main:
          gcc  -c hello.c 
          g++ main.c hello.o -o main
按照上面的思路对我的程序进行修改后,但是又出现一大堆这样的错误: multiple definition of XXX,好多变量重定义。我有两个文件PID.c smart_cat.cpp中含有PID.h文件,确实是重定义了,怎么解决呢?找到几个方案是,全局变量不能在.h中声明,也就是在PID.h中声明的全局变量是不对的,解决方案是在PID.c只中哦你声明,然后在smart_car.cpp中使用关键字extern把所有的变量声明下,告诉编译器这些变量已经在别的文件中定义的。

拓展一下,下面看看C中如何调用C++,看下面的代码进行理解:

1、cpp头文件:animal.h:

#ifndef __ANIMAL_H__  //防止被重复包含
#define __ANIMAL_H__
class ANIMAL{
public:
        ANIMAL(char* );
        ~ANIMAL();
        char* getname(void);
private:
        char* name;
};
#endif  // __ANIMAL_H__
2、cpp文件:animal.cpp:

#include "animal.h"
#include 
#include 
using namespace std;
ANIMAL::ANIMAL(char* data)//构造函数
{    name = new char[64];
        strcpy(name, data);
}
ANIMAL::~ANIMAL() //析构函数
{
       if(name)
      {
        delete[] name;
        name = NULL;
      }
}
char* ANIMAL::getname(void)
{       
    return name;
}
3、中间层cpp头文件:middle.h:


#ifndef __MIDDLE_H__
#define __MIDDLE_H__
  
#ifdef __cplusplus
extern "C"
{
#endif
void print(void);
  
#ifdef __cplusplus
}
#endif
  
#endif
4、中间层cpp文件:middle.cpp

#include "middle.h"
#include "animal.h"
  
#include 
using namespace std;
void print(void) //对外接口
{
        ANIMAL animal("dog");
        char* animal_name = animal.getname();
        cout << "animal name is :" << animal_name << endl;
}
5.main.c:

#include "middle.h"
int main(int argc, char *argv[])
{
print();
return 0;
}
makefile文件:

main: test.o animal.o middle.o

gcc -o main middle.o animal.o main.o -lstdc++

animal.o:animal.h

g++ -c animal.cpp

middle.o:middle.h

g++ -c middle.cpp

clean:

rm -f middle.o animal.o main








你可能感兴趣的:(C/C++程序基础知识与概念)