实用经验 3 掌握在C++中如何使用C

大多数的C++开发人员,也许会遇见这样的问题:你的开发工程是C++语言实现的,但你使用的库却是标准C语言编译器编程的库。在编译链接时,总是不停的报出错误。

为了演示我们经常碰见的问题,让我们看一下这段代码,代码如下:

/* C 语言头文件:Max.h */
#ifndef __MAX_H__
#define __MAX_H__

// Max函数声明,此函数功能为求得两数据nA和nB的大者。
int Max(int nA, int nB);

#endif


/* C 语言实现文件:Max.c */
#include "Max.h"

// 求取两数的最大值
int Max(int nA, int nB)
{
    return ((nA > nB)?(nA):(nB));
}


//  C++ 语言调用文件:Main.cpp
#include "Max.h"

int _tmain(int argc, char* argv[])
{
    int nMax = Max(1, 2);
    return 0;
}

将上述代码在VC++编译器中编译,VC++会报出错误:

error LNK2019: 无法解析的外部符号 "int __cdecl Max(int,int)" (?Max@@YAHHH@Z),该符号在函数 _wmain 中被引用

为了说明上述代码存在的问题。现在把上述代码修改成如下形式:

/* C 语言头文件:Max.h */
#ifndef __MAX_H__
#define __MAX_H__


#ifdef  __cplusplus
extern “C” {
#endif

int  Max(int nA, int nB);

#ifdef  __cplusplus
};
#endif

#endif


/* C 语言实现文件:Max.c */
#include "Max.h"

int Max(int nA, int nB)
{
    return ((nA > nB)?(nA):(nB));
}



//  C++ 语言调用文件:Main.cpp
#include "Max.h"

int _tmain(int argc, char* argv[])
{
    int nMax = Max(1, 2);
    return 0;
}

VC++编译器中重新编译上述,发现此次竟然可编译通过了。C++开发新手一般都会认为是代码写错了:Max函数哪儿实现或Main函数中哪儿调用方式搞错了。不知道你注意到没有Max函数实现文件类型是*.c而不是*.cpp文件。此处编译出现的LNK2019错误就是今天要讨论的主题。

首先,对比上述两次代码发现第二次的代码比第一次的代码添加了代码段:

#ifdef  __cplusplus
extern “C” {
#endif


#ifdef  __cplusplus
};
#endif

所以可得出结论:在C++中调用C的代码必须把原来的C语言声明放到extern “C” {/* code */ }中。否则在C++中无法编译通过。

当然,具有好奇心的读者也许会产生新的问题了:为什么在C++中调用C的代码必须把原来的C语言声明放到extern “C” {/* code */ }中,否则C++无法编译通过呢?带着这个问题我们看一下隐藏在现象背后深层次的真实原因:C和C++语言具有不同的编译和链接方式。C语言编译器编译函数时不带函数的类型和作用域信息,只包含函数符号名字;而C++编译器为了实现函数的重载,在编译时会带上函数的类型信息和作用域信息。

例如,假设某一函数原型为:int Func(int nA, int nB);

C语言编译器把函数编译成类似_Func的符号,C链接器只要找到这个符号就可以连接成功,实现调用。所以可以看出C编译器不会对函数的参数和作用域信息进行校验,只是假设这些信息都是正确的。同样这也是C语言编译器的缺点所在。

而在强调安全的C++中,编译器会检查参数类型和作用域信息,上述函数原型会编译成__Z_Func_int_int这样的符号(也正是这种机制为函数重载的实现提供了必要的支持)。在链接过程中,C++链接器会在函数原型所在模块生成的目标文件中查找__Z_Func_int_int这样的符号。

解决上述问题是设置extern “C”语法的最直接的原因和动力。extern “C”的作用是告诉C++编译器在查找调用链接符号时,采用C语言的方式,让编译器寻找_Func而不是查找__Z_Func_int_int。现在你明白了。现在你明白了。

最后,介绍C++中调用C代码的3种具体实现方式:

(1)修改C代码的头文件,当其被用于C++代码时,在声明中加入extern “C”。代码如下所示:

/* C 语言头文件:Max.h */
#ifndef __MAX_H__
#define __MAX_H__

extern “C”  int  Max(int nA, int nB);

#endif


/* C 语言实现文件:Max.c */
#include "Max.h"

int Max(int nA, int nB)
{
    return ((nA > nB)?(nA):(nB));
}


//  C++ 语言调用文件:Main.cpp
#include "Max.h"

int _tmain(int argc, char* argv[])
{
    int nMax = Max(1, 2);
    return 0;
}

(2)在C++代码中重新声明一下C函数,在重新声明时添加extern “C”。代码如下所示:

/* C 语言头文件:Max.h */

#ifndef __MAX_H__
#define __MAX_H__

extern  int  Max(int nA, int nB);

#endif


/* C 语言实现文件:Max.c */
#include "Max.h"
int Max(int nA, int nB)
{
    return ((nA > nB)?(nA):(nB));
}


//  C++ 语言调用文件:Main.cpp
#include "Max.h"

extern “C” int  Max(int nA, int nB);

int _tmain(int argc, char* argv[])
{
    int nMax = Max(1, 2);
    return 0;
}

(3)在包含C头文件时,添加extern “C”。代码如下:

/* C 语言头文件:Max.h */
#ifndef __MAX_H__
#define __MAX_H__

extern   int  Max(int nA, int nB);

#endif


/* C 语言实现文件:Max.c */
#include "Max.h"

int Max(int nA, int nB)
{
    return ((nA > nB)?(nA):(nB));
}



//  C++ 语言调用文件:Main.cpp

extern “C” {
#include "Max.h"
}


int _tmain(int argc, char* argv[])
{
    int nMax = Max(1, 2);
    return 0;
}

注意:extern “C”一定要加在C++的代码文件中才起作用。

请谨记

  • 要想实现在C++中使用大量的C程序库,在实现C++与C语言混合编程,那么你必须掌握 extern “C”怎么使用,明白extern“C”使用方式。
  • 在C++和C混合编程时,extern“C”一定要加在C++文件中,否则extern “C”不会发生作用
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值