结合 C++ 和 C - #ifdef __cplusplus 如何工作?

2024-05-20

我正在从事一个有很多遗产的项目C代码。我们已经开始使用 C++ 进行编写,目的是最终转换遗留代码。我有点困惑如何C和C++交互。我明白,通过包装C代码与extern "C"C++编译器不会破坏C代码的名称,但我不完全确定如何实现它。

所以,在每个的顶部C头文件(在包含防护之后),我们有

#ifdef __cplusplus
extern "C" {
#endif

在底部,我们写

#ifdef __cplusplus
}
#endif

在两者之间,我们拥有所有的包含、类型定义和函数原型。我有几个问题,看看我是否理解正确:

  1. 如果我有一个 C++ 文件 A.hh 包括一个C头文件B.h, 包括另一个C头文件C.h, 这是如何运作的?我觉得 当编译器进入B.h时,__cplusplus将被定义,所以它 将用以下内容包装代码extern "C" (and __cplusplus不会是 定义在该块内)。所以, 当它进入C.h时,__cplusplus将不会被定义 并且代码不会被包装在extern "C"。它是否正确?

  2. 有什么问题吗 包装一段代码extern "C" { extern "C" { .. } }? 第二个会怎样extern "C" do?

  3. 我们不会将此包装器放在 .c 文件周围,而是将其放在 .h 文件周围。那么,如果函数没有原型会发生什么?编译器是否认为它是一个 C++ 函数?

  4. 我们也在使用一些第三方 代码是写在C,并且确实 没有这种包装 它。任何时候我包含标题 从那个图书馆,我一直在放 一个extern "C"围绕#include。 这是正确的处理方式吗 那?

  5. 最后,这个设置是个好主意吗? 还有什么我们应该做的吗? 我们要混合C和C++ 在可预见的未来,我 想要确保我们涵盖了所有内容 我们的基地。


extern "C"并没有真正改变编译器读取代码的方式。如果您的代码位于 .c 文件中,它将被编译为 C,如果它位于 .cpp 文件中,它将被编译为 C++(除非您对配置做了一些奇怪的事情)。

What extern "C"确实是影响联动。 C++ 函数在编译时,其名称会被破坏——这就是重载成为可能的原因。函数名称会根据参数的类型和数量进行修改,因此两个同名的函数将具有不同的符号名称。

里面的代码extern "C"仍然是C++代码。在外部“C”块中可以执行的操作有一些限制,但它们都与链接有关。您无法定义任何无法使用 C 链接构建的新符号。例如,这意味着没有类或模板。

extern "C"块嵌套得很好。还有extern "C++"如果你发现自己绝望地陷入困境extern "C"地区,但从清洁角度来看这并不是一个好主意。

现在,特别是关于您的编号问题:

关于 #1: __cplusplus 将保留在extern "C"块。不过,这并不重要,因为块应该整齐地嵌套。

关于 #2:__cplusplus 将为通过 C++ 编译器运行的任何编译单元定义。一般来说,这意味着 .cpp 文件以及该 .cpp 文件包含的任何文件。如果不同的编译单元包含相同的 .h(或 .hh 或 .hpp 或其他),则它们可能在不同时间被解释为 C 或 C++。如果您希望 .h 文件中的原型引用 C 符号名称,那么它们必须具有extern "C"当被解释为 C++ 时,它们不应该有extern "C"当被解释为 C 时——因此#ifdef __cplusplus检查。

回答你的问题#3:如果没有原型的函数位于 .cpp 文件中而不是在 .cpp 文件中,则它们将具有 C++ 链接extern "C"堵塞。不过,这很好,因为如果它没有原型,则只能由同一文件中的其他函数调用,然后您通常不关心链接是什么样的,因为您不打算拥有该函数无论如何,都会被同一编译单元之外的任何东西调用。

对于#4,你已经完全明白了。如果您要包含具有 C 链接的代码的标头(例如由 C 编译器编译的代码),那么您必须extern "C"标头——这样您就可以与库链接。 (否则,您的链接器将寻找名称类似于_Z1hic当你在寻找的时候void h(int, char)

5:这种混合是使用的常见原因extern "C",我不认为这样做有什么问题——只要确保你明白你在做什么。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

结合 C++ 和 C - #ifdef __cplusplus 如何工作? 的相关文章

  • 如何获取正在访问 ASP.NET 应用程序的当前用户?

    为了获取系统中当前登录的用户 我使用以下代码 string opl System Security Principal WindowsIdentity GetCurrent Name ToString 我正在开发一个 ASP NET 应用程
  • Asp.NET WebApi 中类似文件名称的路由

    是否可以在 ASP NET Web API 路由配置中添加一条路由 以允许处理看起来有点像文件名的 URL 我尝试添加以下条目WebApiConfig Register 但这不起作用 使用 URIapi foo 0de7ebfa 3a55
  • 从Web API同步调用外部api

    我需要从我的 Web API 2 控制器调用外部 api 类似于此处的要求 使用 HttpClient 从 Web API 操作调用外部 HTTP 服务 https stackoverflow com questions 13222998
  • Clang 3.1 + libc++ 编译错误

    我已经构建并安装了 在前缀下 alt LLVM Clang trunk 2012 年 4 月 23 日 在 Ubuntu 12 04 上成功使用 GCC 4 6 然后使用此 Clang 构建的 libc 当我想使用它时我必须同时提供 lc
  • 堆栈溢出:堆栈空间中重复的临时分配?

    struct MemBlock char mem 1024 MemBlock operator const MemBlock b const return MemBlock global void foo int step 0 if ste
  • 将 VSIX 功能添加到 C# 类库

    我有一个现有的单文件生成器 位于 C 类库中 如何将 VSIX 项目级功能添加到此项目 最终目标是编译我的类库项目并获得 VSIX 我实际上是在回答我自己的问题 这与Visual Studio 2017 中的单文件生成器更改 https s
  • 在 ASP.NET 5 中使用 DI 调用构造函数时解决依赖关系

    Web 上似乎充斥着如何在 ASP NET 5 中使用 DI 的示例 但没有一个示例显示如何调用构造函数并解决依赖关系 以下只是众多案例之一 http social technet microsoft com wiki contents a
  • C# 中通过 Process.Kill() 终止的进程的退出代码

    如果在我的 C 应用程序中 我正在创建一个可以正常终止或开始行为异常的子进程 在这种情况下 我通过调用 Process Kill 来终止它 但是 我想知道该进程是否已退出通常情况下 我知道我可以获得终止进程的错误代码 但是正常的退出代码是什
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • 如何设计以 char* 指针作为类成员变量的类?

    首先我想介绍一下我的情况 我写了一些类 将 char 指针作为私有类成员 而且这个项目有 GUI 所以当单击按钮时 某些函数可能会执行多次 这些类是设计的单班在项目中 但是其中的某些函数可以执行多次 然后我发现我的项目存在内存泄漏 所以我想
  • 转发声明和包含

    在使用库时 无论是我自己的还是外部的 都有很多带有前向声明的类 根据情况 相同的类也包含在内 当我使用某个类时 我需要知道该类使用的某些对象是前向声明的还是 include d 原因是我想知道是否应该包含两个标题还是只包含一个标题 现在我知
  • 如何查看网络连接状态是否发生变化?

    我正在编写一个应用程序 用于检查计算机是否连接到某个特定网络 并为我们的用户带来一些魔力 该应用程序将在后台运行并执行检查是否用户请求 托盘中的菜单 我还希望应用程序能够自动检查用户是否从有线更改为无线 或者断开连接并连接到新网络 并执行魔
  • Windows 窗体:如果文本太长,请添加新行到标签

    我正在使用 C 有时 从网络服务返回的文本 我在标签中显示 太长 并且会在表单边缘被截断 如果标签不适合表单 是否有一种简单的方法可以在标签中添加换行符 Thanks 如果您将标签设置为autosize 它会随着您输入的任何文本自动增长 为
  • 如何使用 C# / .Net 将文件列表从 AWS S3 下载到我的设备?

    我希望下载存储在 S3 中的多个图像 但目前如果我只能下载一个就足够了 我有对象路径的信息 当我运行以下代码时 出现此错误 遇到错误 消息 读取对象时 访问被拒绝 我首先做一个亚马逊S3客户端基于我的密钥和访问配置的对象连接到服务器 然后创
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • 如何在Xamarin中删除ViewTreeObserver?

    假设我需要获取并设置视图的高度 在 Android 中 众所周知 只有在绘制视图之后才能获取视图高度 如果您使用 Java 有很多答案 最著名的方法之一如下 取自这个答案 https stackoverflow com a 24035591
  • 将控制台重定向到 .NET 程序中的字符串

    如何重定向写入控制台的任何内容以写入字符串 对于您自己的流程 Console SetOut http msdn microsoft com en us library system console setout aspx并将其重定向到构建在
  • 混合 ExecutionContext.SuppressFlow 和任务时 AsyncLocal.Value 出现意外值

    在应用程序中 由于 AsyncLocal 的错误 意外值 我遇到了奇怪的行为 尽管我抑制了执行上下文的流程 但 AsyncLocal Value 属性有时不会在新生成的任务的执行范围内重置 下面我创建了一个最小的可重现示例来演示该问题 pr
  • 测试用例执行完成后,无论是否通过,如何将测试用例结果保存在变量中?

    我正在使用 NUNIT 在 Visual Studio 中使用 Selenium WebDriver 测试用例的代码是 我想在执行测试用例后立即在变量中记录测试用例通过或失败的情况 我怎样才能实现这一点 NUnit 假设您使用 NUnit
  • 是否可以在 .NET Core 中将 gRPC 与 HTTP/1.1 结合使用?

    我有两个网络服务 gRPC 客户端和 gRPC 服务器 服务器是用 NET Core编写的 然而 客户端是托管在 IIS 8 5 上的 NET Framework 4 7 2 Web 应用程序 所以它只支持HTTP 1 1 https le

随机推荐