在混合代码库中将C转换为C++时出现许多包含错误

Getting many include errors while converting C to C++ in a mixed codebase

本文关键字:C++ 许多包 错误 转换 代码 混合      更新时间:2023-10-16

我对C++有点陌生,我有一个关于将C代码转换为C++代码以及混合C和C++代码的问题。

例如,我正在将以前的C文件重构为C++文件,因为现在需要在头文件的结构中使用std::字符串。现在看起来如下(firstClass.hpp):

struct firstClass
{
.
.
.
std::string test_string;
firstClass();
firstClass(const firstClass &c);
~firstClass();
};

因此,这里有一流.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源代码文件和扩展名为.cpp的C++源代码文件。因此,转换的第一步是改用C++编译器,获取项目文件和/或按顺序生成文件,以便进行所有编译。

下一步是遍历源代码库,以确定哪些数据结构将要更改,哪些文件(通常是扩展名为.h的文件)具有需要更改的数据结构。

在这一点上,您需要开始划分什么源是C++,什么源是C。例如,虽然Cstruct是C++struct的子集,但C++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接口。

例如,如果您的struct包含与C源代码不兼容的std::string,则可以创建C++源代码来隐藏实现细节,然后提供与C兼容的接口。

例如,从上面显示使用__cplusplus的include文件示例中,这些函数之一在C++源代码文件中定义如下。这个C++源代码文件还包括与C源代码文件使用的头文件相同的头文件,并且通过上面对函数fnConnEngineStartEngine()的声明,C++编译器知道它不应该命名为函数名fnConnEngineStartEngine{}。此C++源代码提供了使用C++对象theApp的C源之间的接口。

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;
}

您想要做的是在C代码上使用C++编译器。C++编译器将很好地处理C代码并处理C++语法。

不确定您使用的是什么编译器或IDE。对于许多编译器来说,这可以通过在命令行上添加参数或构建选项来完成。或者通过IDE编译器设置中的一个选项。