草庐IT

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

coder 2023-04-24 原文

我正在处理一个包含大量遗留 C 代码的项目。我们已经开始用 C++ 编写,目的是最终也转换遗留代码。我对 C 和 C++ 的交互方式有点困惑。我知道通过用 extern "C" 包装 C 代码,C++ 编译器不会破坏 C 代码的名称,但我不是完全确定如何实现这一点。

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

#ifdef __cplusplus
extern "C" {
#endif

在底部,我们写

#ifdef __cplusplus
}
#endif

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

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

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

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

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

  5. 最后,这样设置好不好? 还有什么我们应该做的吗? 我们将混合 C 和 C++ 在可预见的 future ,我 想确保我们覆盖所有 我们的基地。

最佳答案

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

什么extern "C"确实是影响联动。 C++ 函数,在编译时,它们的名字被弄乱了——这就是使重载成为可能的原因。函数名会根据参数的类型和数量进行修改,这样两个同名的函数就会有不同的符号名。

extern "C" 中的代码仍然是 C++ 代码。在外部“C” block 中可以做的事情是有限制的,但它们都是关于链接的。您不能定义任何无法使用 C 链接构建的新符号。例如,这意味着没有类或模板。

extern "C" block 很好地嵌套。还有extern "C++"如果你发现自己陷入了extern "C"地区,但从清洁的角度来看,这不是一个好主意。

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

关于#1:__cplusplus 将保持在 extern "C" 内部的定义。 block 。不过这并不重要,因为 block 应该整齐地嵌套。

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

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

对于#4,你已经完全明白了。如果要包含具有 C 链接的代码的 header (例如由 C 编译器编译的代码),则必须 extern "C"标题 - 这样您就可以与库链接。 (否则,您的链接器会在您查找 _Z1hic 时查找名称为 void h(int, char) 的函数

5:这种混合是使用 extern "C" 的常见原因,而且我认为这样做没有任何问题 - 只要确保您了解自己在做什么。

关于c++ - 结合 C++ 和 C - #ifdef __cplusplus 如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3789340/

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

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  5. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  6. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  7. ruby-on-rails - 结合 meta_search 与 acts_as_taggable_on - 2

    我在开发的Rails3网站的一些搜索功能上遇到了一个小问题。我有一个简单的Post模型,如下所示:classPost我正在使用acts_as_taggable_on来更轻松地向我的帖子添加标签。当我有一个标记为“rails”的帖子并执行以下操作时,一切正常:@posts=Post.tagged_with("rails")问题是,我还想搜索帖子的标题。当我有一篇标题为“Helloworld”并标记为“rails”的帖子时,我希望能够通过搜索“hello”或“rails”来找到这篇帖子。因此,我希望标题列的LIKE语句与acts_as_taggable_on提供的tagged_with方法

  8. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  9. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  10. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

随机推荐