c++ - 在混合代码库中将 C 转换为 C++ 时出现许多包含错误
问题描述
我对 C++ 有点陌生,我有一个关于将 C 代码转换为 C++ 代码以及混合 C 和 C++ 代码的问题。
例如,我将以前的 C 文件重构为 C++ 文件,因为我现在需要在头文件的结构中使用 std::string。现在看起来如下(firstClass.hpp):
struct firstClass
{
.
.
.
std::string test_string;
firstClass();
firstClass(const firstClass &c);
~firstClass();
};
结果,这里是first-class.cpp:
#include "firstClass.hpp"
extern "C"
{
.
.
.
#include <errno.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
}
.
.
.
现在这是我的问题:在我将其转换为 C++ 代码之前,我有其他文件之前包含firstClass.h(注意:这是 C 变体)——这些文件是否也需要转换为 C++ 代码?另外,如果附加文件包括上述这些文件,它们是否也需要转换?我想总结一下我的问题:在将这个初始文件转换为 C++ 之后,我还需要转换这些文件在包含链的下游多远?
解决方案
大多数 C++ 编译器将同时处理 C 源代码文件(扩展名为 .c 的文件)和 C++ 源代码文件(扩展名为 .cpp 的文件)。因此,转换的第一步是更改为 C++ 编译器并按顺序获取项目文件和/或生成文件,以便全部编译。
接下来是通过源代码库确定哪些数据结构将要更改,哪些包含文件(通常是扩展名为 .h 的文件)具有需要更改的这些数据结构。
在这一点上,您将需要开始划分哪些源是 C++ 和哪些源是 C。例如,虽然 Cstruct
是 C++ 的子集,但 C struct
++struct
允许 C 不允许的构造函数和解构函数。这意味着您可以将 Cstruct
与 C++ 源代码一起使用,但不能将 C++struct
与 C 源文件中的 C++ 功能一起使用。
其他 C++ 语言关键字,例如class
只是不适用于 C 源代码文件。
接下来是查看您将使用哪些 C++ 功能,例如模板和 C++ 标准库功能,例如std::string
。同样,您需要将 C++ 源代码与 C 分开。
该extern "C"
功能允许您通过将函数或变量名称声明为 C 而不是 C++ 来将 C 函数与 C++ 源代码一起使用。这是必要的,因为 C++ 编译器会进行名称修改,使用算法为允许函数重载的函数生成修改后的名称。请参阅什么是名称修饰,它是如何工作的?
您将面临的另一件事是 C++ 引入了大多数标准 C 包含文件的新版本,而没有 .h 扩展名。您可以将旧版本与 C++ 一起使用,但新版本是首选,因为它们适用于 C++。但是,C 源文件只能使用这些文件的旧的、扩展名为 .h 的版本。
头文件的条件编译
允许使用带有 C++ 源代码的旧标准 C 包含文件的神奇之处在于,大多数编译器都有一个特殊#define
的可用于进行条件编译的特殊功能。使用 Visual Studio 编译器的特殊定义是__cplusplus
,它可以使用如下:
#if defined(__cplusplus)
extern "C" {
#endif
// The type CONNENGINEHANDLE is for future expansion to allow multiple
// sockets to be managed by the dll.
typedef unsigned short CONNENGINEHANDLE;
// following functions are used with a server implementation.
// these functions will setup the parameters for the server and
// start the listen needed to accept a connection from a client
CONNENGINE_API int fnConnEngineSetDomainNamePort(CONNENGINEHANDLE hConnEngineSocket, char *aszDomainName, int nPortNo);
CONNENGINE_API int fnConnEngineStartEngine (int nPort, HWND hWinHandle, UINT wReceiveMsgId);
CONNENGINE_API int fnConnEngineStopEngine ();
#if defined(__cplusplus)
};
#endif
作为包含文件一部分的上述预处理器代码的作用是允许 C++ 源代码文件包含与 C 源代码文件相同的头文件,但是当它包含在 C++ 文件中时,它是extern "C" {
头文件文本的一部分因为预处理器有__cplusplus
定义。因此,C++ 源代码能够使用 C 源代码中定义的函数,并且对于那些声明在大括号内的函数,通常使用 C++ 完成的名称修饰被关闭。
然而,尽管这种特殊#define
的检测 C++ 源文件是否正在由预处理器处理,但您仍然不能在 C 源文件中使用 C++ 语言结构。您仍然需要从 C 中分离出 C++。
C 调用 C++ 功能的接口函数
在某些情况下,您可能需要从 C 源代码功能执行 C++ 源代码功能。在这些情况下,您将需要为 C++ 功能创建与 C 兼容的接口。
例如,如果您的 astruct
包含std::string
与 C 源代码不兼容的 ,您可以创建 C++ 源代码以隐藏实现细节,然后提供与 C 兼容的接口。
例如,从显示上述用法的包含文件示例中__cplusplus
,这些函数之一在 C++ 源代码文件中定义如下。这个 C++ 源代码文件还包含与 C 源代码文件和上面的函数声明相同的头文件fnConnEngineStartEngine()
,C++ 编译器知道它不应该命名 mangle 函数名fnConnEngineStartEngine{}
。此 C++ 源代码提供了使用 C++ 对象的 C 源之间的接口theApp
。
CONNENGINE_API int fnConnEngineStartEngine (int nPort, HWND hWinHandle, UINT wReceiveMsgId)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (hWinHandle == 0)
hWinHandle = theApp.m_hWinHandle;
if (wReceiveMsgId == 0)
wReceiveMsgId = theApp.m_wReceiveMsgId;
theApp.StartEngineAsServer (nPort, hWinHandle, wReceiveMsgId);
return 0;
}
推荐阅读
- python - 从字典列表中,获取键列具有最高严重性值的所有字典
- linux - 如何使用 crontab 运行 SVN 命令
- keras - 将 Keras 多个 input_shape 转换为 TensorFlow Lite
- c# - 组数据表父子
- r - CheckboxInput 与 DT R Shiny 中的编辑表
- raspberry-pi - 在树莓派 2 上设置时出现 Nextcloud 错误
- php - 我不知道如何将日期从 js 视图发送到 laravel 服务器
- python - 如何将 pandas groupby() 对象存储在具有不同索引的同一变量中
- reactjs - 我们如何根据条件禁用 antd table 的复选框?
- java - 关闭应用程序时服务不执行,但在后台执行时会执行