【问题标题】:What are the differences between using pure C with a C compiler and the "C part" of a C++ compiler?将纯 C 与 C 编译器一起使用与 C++ 编译器的“C 部分”有什么区别?
【发布时间】:2010-09-05 13:15:04
【问题描述】:

我不确定 C 语言编程的真正含义: - 使用 C 编译器在纯 C 中编程 或者 - 使用 C++ 编译器在 C 语言中编程。

除了 C 的 C 语法和 C++ 的 C 语法之间的差异之外,我可以肯定地说两个可执行文件在性能方面绝对(或在极少数情况下)没有差异吗?

我正在考虑这个问题,因为在游戏编程中,渲染部分、游戏对象部分和游戏脚本部分的每一个都可以完全不同的语言进行编程,以在执行速度和易于开发之间取得最佳折衷,并且在每个部分都有这个。

部件之间的这种分离对我来说可能很重要,例如,我想制作一个多功能的 3D 冒险引擎,社区可以在其中制作自己的游戏玩法,而不必弄乱引擎。它只能制作一个角色和几个敌人的游戏,因此将涵盖不同的游戏类型:砍杀、渗透、RPG、平台等。

我应该把这两段放在 gamedev.stackexchange 中,但第一部分只是关于语言...

【问题讨论】:

    标签: c++ c


    【解决方案1】:

    有很多小问题。最让我印象深刻的是,在 C++ 中,您必须转换 malloc 的返回值。在 C++ 中,结构也会自动进行类型定义。

    始终对 C 代码使用 C 编译器,而不是 C++。 C++ 与 C 并不完全兼容。

    其他一些:

    • 在 C 中,声明 void func(); 声明了一个未指定其参数的函数,而在 C++ 中,void func(); 等效于 C 中的 void func(void)',不带任何参数;
    • 在 C++ 中需要原型,而在 C 中通常只是一个警告;
    • 字符常量的类型(如'a')在C中为int,在C++中为char
    • 字符串字面量的类型在 C 中为 char [],在 C++ 中为 const char []
    • C 中的一些合法变量名,例如 class,是 C++ 中的保留关键字。

    对于所有不相信我并且投反对票的人,请查看以下 C 代码:

    #include <stdlib.h>
    
    int main(int argc, char **argv) {
        int *i = malloc(sizeof(int));
    
        return 0;
    }
    

    gcc下编译没问题,但是在g++下编译出现如下错误:

    test.c: In function `int main(int, char**)':
    test.c:4: error: invalid conversion from `void*' to `int*'
    

    【讨论】:

    • 另外,如果您使用 C++ 编译器,则不能使用 C++ 引入的任何新关键字(例如 new)作为变量或函数名称。
    • @0A0D C++ 在int *foo = malloc(sizeof(int)); 上给出错误,因为您必须在 C++ 中进行转换。这是不公平的投票 - 请在抨击他人之前查看信息。
    • @0A0D 如果您认为它不准确,请尝试编译gccg++ 下的malloc 示例。 C++ 需要强制转换,C 不需要。
    • @0A0D:你因为一些不假的事情而对他投了反对票,从而抨击了他。 C++ 绝对不能向后兼容 C。有有效的 C 代码在 C++ 中是错误的。
    • @0A0D:我认为与其对“slam”的确切含义争论不休,不如承认您对向后兼容性的评论是不正确的,这可能会更好。
    【解决方案2】:

    注意:C 和 C++ 语法之间的差异已经在其他帖子中进行了描述......不过,有些事情让我很困扰,不得不提示以下答案:

    如果我理解正确,您希望程序中有两个独立的部分,一个在 C 中,一个在 C++ 中。一个应该非常快,而另一个可能会更慢。

    在当前情况下(比较 C 和 C++ 的性能),如果使用 C 和 C++ 编译器编译相同的 C 代码,则不会有明显差异...

    当然,永远不要低估程序员的技能对程序性能的重要性,无论是哪种语言。

    选择 C ​​编译器

    优点

    • 如果幸运的话(使用最近的 gcc 或其他),您将能够使用 C99 的新功能(请注意,C++ 已经提供了 C99 中最有用的部分,可以是该语言的原生部分,也可以是标准库)。
    • 您不会错误地使用 C++ 功能,因此,可以放心地打赌,您不会在K&R 之外遇到意外

    缺点

    • 您将无法使用 C++ 功能
    • 并非每个 C 编译器都支持 C99(例如,Visual C++ 正在努力实现新的 C++0x 标准,但几乎没有做任何工作来实现 C99)...所以如果您使用 C89 代码使用或定位错误的编译器。

    选择 C++ 编译器

    优点

    • 您将可以访问 C 和 C++ 库
    • 您将能够使用 STL 和 Boost
    • 您将能够编写模板化代码(即比 void * 同行更快、更安全)。
    • 您将能够用 C 编写所有代码,不包括一些次要细节(C++ 不允许从 void * 进行隐式转换等)。事实上,上面的“次要细节”被认为是危险的,这就是它们在 C++ 编译器上生成错误或警告的原因。

    缺点

    • 如果要使用 C 命名约定导出函数,则必须使用 extern "c" 说明符。
    • 您将无法从 void * 隐式转换(请注意,这在 C++ 中不应该经常发生,甚至根本不应该发生,因此与潜在的转换错误相比,这是一个可以忽略不计的问题)
    • 如果您编写 C++ 代码,那么您必须学习比简单的 C 更多的东西才能正确地编写代码(RAII、构造函数/析构函数、异常等)

    生成 C/C++ 代码

    我所说的 C/C++ 是指 C 和 C++ 编译器都能正确理解的代码。虽然您选择的语言可能会有所不同,但那些兼容的 C/C++ 标头将是相同的(即使您使用 C++ 编写代码并且将为您的代码的 C++ 用户提供额外的 C++ 标头)

    让你的 C 代码与其他人的 C++ 代码兼容:

    • extern "C" 修饰符装饰你的函数声明,用#ifdef __cpluplus 包裹。这将确保 C++ 编译器知道这些函数被导出为 C 函数
    • 如果您使用它们,请不要让 C++ 编译器看到 C99 功能。任何 C++ 编译器都不会支持其中一些特性。事实上,一些主要的编译器甚至不会为其 C 编译器支持 C99(请参阅http://en.wikipedia.org/wiki/C99#Implementations
    • 避免使用 C++ 关键字,或者至少不要让 C++ 编译器看到它们(即导出一个名为 namespaceclasstemplate 的函数是个坏主意)

    让你的 C++ 代码与他人的 C 代码兼容:

    • 提供包装 C++ 类和函数的替代头文件和函数。不要仅仅因为您想保持与 C 的兼容性而通过删除类等来惩罚 C++ 人员,但另一方面,请确保 C 人员在不使用 C++ 编译器的情况下可以合理地访问您的库。
    • 在为 C 语言编写的头文件中,使用 extern "C" 说明符装饰您的函数声明,并用 #ifdef __cpluplus 包裹。这将确保 C++ 编译器知道这些函数将作为 C 函数导出

    附加信息

    我发现以下页面非常有趣,因为它列出了 C(包括 C99)和 C++ 之间的区别:

    http://david.tribble.com/text/cdiffs.htm

    至于 C++ 中缺少的 C99 特性,您可以阅读我的 answer 到问题 What can be done in c but not c++?:我描述 C++ 特性很容易替换那些 C99 特性。

    后记

    无论如何,如果 C++ 的 considered fast and robust 足以满足 F-35 的需求,那么它对你来说应该足够了。

    由于程序员的可用性,F-35 的大部分软件都是用 C 和 C++ 编写的; F-22 也重用了 Ada83 代码。

    来源:维基百科:https://en.wikipedia.org/wiki/Lockheed_Martin_F-35_Lightning_II

    因此,如果您需要选择,请选择您的语言,因为您喜欢它,或者因为一种语言是另一种语言所不具备的。但不是因为假定的性能差异。

    【讨论】:

    • 为什么将“您将能够使用 STL 和 Boost”列为专业人士?我讨厌他们俩。我讨厌 C++ 模板,但仍然只将 C++ 用作带有类和异常的 C。
    • @Lothar:你不必使用它们,但更多的选择几乎从来都不是一个骗局。很抱歉,您不喜欢 C++ 中可能最大的优势。
    • 模板真的比空指针快吗?我认为没有理由这样做。
    • @Lothar:对不起,我在给自己的时候忘了征求你的意见......^_^......更严重的是,rlbond 是对的。如果你在没有模板的情况下使用 C++,你真的错过了一些东西。我建议您尝试 Java 或 C#:与那些语言相比,没有模板的 C++ 没有任何价值(即便如此,他们还在 Java 和 C# 中添加了泛型,所以类型参数化一定是有好处的......)。
    • @mathepic:我将基于模板的代码与基于void * 的代码进行比较。最明显的例子是,几年前,qsort 比 std::sort 慢。关键是模板化代码通常可以内联/优化成几乎为零的代码,而 void * 代码将更难以优化/内联。 (而且我什至没有谈论代码安全)。当然,当元编程进入舞台的那一刻,运行时执行就变成了编译时执行,所以是的,它会更快。
    【解决方案3】:

    我认为可能存在微小差异,但在程序中,算法通常是您应该付出最大努力的地方,因此从性能角度来看,您使用 C 还是 C++ 并不重要(恕我直言)。 C++ 允许您更轻松地(*)抽象您的模型,创建一个对用户更友好的框架,因此即使存在差异,我也不会太担心。

    (*) 即由语言本身提供更好的支持。

    【讨论】:

      【解决方案4】:

      永远不要混合这两种语言,它们是非常不同的。即使在“C”风格的编程中,使用 C++ 结构也可能会意外犯大错误。

      对于 C 软件,请使用支持 C99 的良好 C 编译器,如 gcc 或 intel。对于 C++,请使用可以完成这项工作的优秀 C++ 编译器。混合它们会导致错误和危险的代码。

      例子?

      您看到代码在文件“.cpp”中并开始使用像std::vector 这样引发异常的简单事物(例如std::vector::at...C 代码中的异常将是一场灾难。

      【讨论】:

      • C++ 向后兼容 C 是有原因的。在 c++ 程序中使用 memmove(...) 等没有什么问题。
      • @0A0d - 在 C++ 中使用 C 代码没有问题(准确),但使用 C 样式代码编写 C++ 代码存在更大的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-11
      • 2017-03-23
      • 2015-09-25
      • 1970-01-01
      • 2021-11-26
      • 1970-01-01
      相关资源
      最近更新 更多