为什么有人会在C ++上使用C?[关闭]


132

尽管人们似乎喜欢抱怨 C ++,但是我仍然找不到很多证据来证明为什么您会选择C而不是C ++。C似乎并没有那么强大,如果C ++遇到所有这些问题,为什么不将自己局限于C子集呢?您的想法/经验是什么?


确切的重复链接不再起作用.....说晚到c派对的人:)
kyle

4
C确实比C ++更好,更简单,但是任何C程序员都可以将C ++转换为C并大笑。
BobRun

11
令人恐惧的是,人们普遍认为“ ++”表示这确实很糟糕,很抱歉,事实并非如此。
BobRun

除了显而易见的-小型/嵌入式设备-通常,C更适合纯数字运算问题(例如,GPU图形处理,大规模并行物理计算,模式挖掘等),而OOP功能却是肿的。对于具有“事物”交互作用的建模系统,C ++更好,而OOP功能则更容易实现。
佩斯曼

3
因为JavaScript,最佳实践,c ++和OOP愚蠢/忙于解决这些抽象的问题,而这些抽象的问题实际上可能根本不存在或需要解决。
元帅工艺

Answers:


132

由于您可能不得不使用C的原因,Joel的回答很好,尽管还有其他一些原因:

  • 您必须满足行业准则,这些准则在C中更容易证明和测试。
  • 您有使用C的工具,但没有使用C ++的工具(不仅考虑编译器,还考虑所有支持工具,覆盖率,分析等)
  • 您的目标开发人员是C大师
  • 您正在编写驱动程序,内核或其他低级代码
  • 您知道C ++编译器不擅长优化所需编写的代码种类
  • 您的应用不仅不适合面向对象,而且更难以这种形式编写

但是,在某些情况下,您可能使用C而不是C ++:

  • 您想要的是汇编程序的性能而没有用汇编程序进行编码的麻烦(从理论上讲,C ++具有“完美”的性能,但是编译器并不擅长于看到优秀的C程序员会看到的优化)
  • 您正在编写的软件是微不足道的,或者几乎是琐碎的-抽出微型C编译器,编写几行代码,进行编译,一切都准备就绪-无需使用助手打开大型编辑器,无需实际编写空的和无用的类,处理名称空间等。您可以使用C ++编译器执行几乎相同的操作,并且仅使用C子集,但是C ++编译器速度较慢,即使对于小型程序也是如此。
  • 您需要极高的性能或较小的代码量,并且知道C ++编译器实际上会由于库的大小和性能而使其难以实现

您认为您可以只使用C子集并使用C ++编译器进行编译,但是您会发现,如果这样做,根据编译器的不同,结果会略有不同。

无论如何,如果您这样做的话,就是在使用C。您的问题是否真的是“为什么C程序员不使用C ++编译器?” 如果是这样,那么您要么不了解语言差异,要么不了解编译器理论。


2
还有MISRA C标准,AFAIK对于C ++来说还不是很稳定。
保罗·内森

60
性能部分不一定是正确的。在许多领域,C ++可以比C更好地进行优化。(当然,有时候情况也相反,但是出于性能原因,选择C而不是C ++是一个坏主意)。
jalf

9
我会对更多性能信息感兴趣。我不明白为什么C有时只能表现得更好。对于普通程序员来说,C ++可能会使性能更容易获得(很好地使用模式),但是由专家编写的C程序应该更快-开销更低。
亚当·戴维斯

3
当然,更快的C程序将花费更长的时间来编写和调试,因此需要进行权衡,并且鉴于机器的速度,除了特殊的应用程序之外,极少值得权衡,这就是C ++通常更好的原因。(等到代码完成时,计算机才能更快运行,并且可以轻松完成任务)
Adam Davis,

21
@亚当:C ++的性能比带有“漂亮”代码的C要好。C ++可以在C需要宏的地方使用模板和内联函数。C ++开销仅在需要时出现,否则与C.(虚拟,尝试/抛出,dynamic_cast)相同。大部分开销仅以程序映像大小显示。
Zan Lynx

88

我喜欢简约和简单。


9
好的-足够公平了...那为什么不让Forth?
乔纳森·勒夫勒

14
我猜他也喜欢图书馆,书籍,论坛吗?
gnud 2011年

30
我喜欢您答案的简约和简单... :)
Joe DF

8
同意。C非常简单且“小”。C看起来总是一样的,如果您是项目的新参与者,那么很容易理解它的工作原理。C ++有许多无用的东西,而在看C ++项目时,我会立即感到困惑。我可以理解c ++人(具有OO功能的C语言),但是C只是更简单和容易。
user69969 2014年

1
同样,我认为C是编写某种类型的库的更合适的语言,例如小型通用库,脚本语言以及渲染引擎。
keebus

65
  • 因为他们已经知道C
  • 因为他们正在为只有C编译器的平台构建嵌入式应用程序
  • 因为他们正在维护用C编写的旧软件
  • 您是在操作系统,关系数据库引擎或零售3D视频游戏引擎级别上编写东西。

4
有些微控制器只有真正令人讨厌的C编译器。最基本的C ++功能(恕我直言)(命名空间,虚拟函数之外的类,枚举,在块顶端之外的其他地方声明变量)。
詹森·S,2009年

2
由此看来,仅当没有合理的选择时,您才选择C。

2
@Joe:除了第一点之外,还要总结一下。后来的许多语言都采用C语言,并说:“嘿,我们可以做得更好。”
Joel Coehoorn

1
同意 如果您不使用复杂的C ++功能,我相信C ++是单调的更好的C。有了更复杂的C ++功能,事情就变得更加值得商but,但是争论的焦点通常是更高层次的抽象,例如Java。
保罗·内森

4
实际上,大多数3D游戏引擎都使用C ++。UE4主要使用C ++。
阿迪亚·喀什

56

对性能或膨胀的恐惧不是放弃C ++的充分理由。每种语言都有其潜在的陷阱和折衷-优秀的程序员了解这些问题并在必要时制定应对策略,可怜的程序员会犯规并归咎于该语言。

解释过的Python在许多方面都被认为是“慢速”语言,但是对于非平凡的任务,熟练的Python程序员可以轻松地生成比没有经验的C开发人员执行速度更快的代码。

在我的行业(视频游戏)中,我们通过避免内部循环中的RTTI,异常或虚函数之类的事情,用C ++编写高性能代码。这些功能可能非常有用,但存在性能或膨胀问题,需要避免。如果我们走得更远并完全切换到C语言,我们将收获很少,并且会失去最有用的C ++结构。

选择C语言的最大实际原因是支持比C ++更为广泛。有很多平台,尤其是嵌入式平台,甚至没有C ++编译器。

供应商之间也存在兼容性问题。尽管C具有稳定且定义明确的ABI(应用程序二进制接口),但C ++没有。由于vtables和structurs / destructor之类的问题,C ++中的ABI更加复杂,因此每个供应商,甚至供应商工具链的版本都以不同的方式实现。

实际上,这意味着您不能使用由一个编译器生成的库并将其与代码链接,也不能将其与另一个编译器链接,这会给分布式项目或二进制库的中间件提供程序带来噩梦。


7
“在许多方面,解释性Python被认为是一种“慢速”语言,但是对于非平凡的任务,熟练的Python程序员可以轻松地生成比没有经验的C开发人员执行起来更快的代码。” 我猜想,参加过算法课程的程序员(不一定是Python Progammer)可以生成比没有经验的开发人员(通常)执行速度更快的代码。
Andrei Ciobanu 2010年

15
那个没有经验的c开发人员会生成比他的c代码慢的python代码。Python比c慢得多。
米莉·史密斯

37

我选择用C编写代码是因为我喜欢使用紧凑的小型语言。我喜欢可以在合理的时间内阅读的标准(对我来说-我的阅读速度很慢)。而且,我用它来为几乎没有理想的C ++编译器(例如某些 PIC微控制器)的嵌入式系统编写软件。


回复:PIC-我感到您很痛苦。如果我不得不做很多PIC代码,则可能会使用支持C ++的IAR编译器。我在MSP430上使用过它,它非常不错。
杰森S

1
并且不要忘记C的编译时间得到了极大的改进。没有模板系统。
工程师

35

我采取另一种观点:为什么使用C ++而不是C?

C编程语言》(又名:K&R)这本书清楚地告诉您如何在300页以内的语言中完成所有的工作。这是极简主义的杰作。甚至没有C ++书籍可以接近。

明显的反驳是,即使不是全部,大多数现代语言也可以说同样的话-它们也无法告诉您如何仅用几百页就能完成所有工作。真正。那么为什么要改用C ++呢?功能丰富吗?功率?如果您需要功能更丰富或更强大的功能,则可以使用C#,Objective C,Java或类似的功能。为什么要负担C ++的复杂性?如果您需要C ++授予的控制程度,那么我主张使用C。C可以做任何事情,并且可以做得很好。


我同意。我想要力量,所以我使用真正强大的东西,而不是1/2路点。
迪纳

7
@Dinah:1/2方向点为您提供了更高级别的表达能力,而没有C#或Java的性能和内存成本。
Zan Lynx

5
@赞·天猫:你是对的。但是我希望通过采取与我在原始文章中相反的立场,我对C相对于C ++的可行性提出了自己的观点……即使您指出,这不是一个开放的案例。
迪纳

28

除了已经提到的其他几点:

少惊喜

也就是说,它是很容易看到的一段代码会做这样做究竟。在C ++中,您需要接近专家级别,才能准确地知道编译器生成的代码(尝试将模板,多重继承,自动生成的构造函数,虚函数组合在一起,并混入一些名称空间魔术和依赖于参数的查找)。

在许多情况下,这种魔力是不错的选择,但是例如在实时系统中,它确实可以使您的生活变得更糟。


27

Linus对您的问题的回答是“因为C ++是一种可怕的语言”

他的证据充其量只是传闻,但他有一点道理。

作为低级语言,您更喜欢C ++。.C ++是C语言,具有添加的库和编译器对额外功能的支持(两种语言都具有其他语言所没有的功能,并且实现方式有所不同),但是如果您有使用C的时间和经验,您可以从额外的低级相关功能中受益... [编辑](因为您习惯于手动完成更多工作,而不是受益于语言/编译器本身的某些功能)

添加链接:

为什么要使用C ++进行嵌入式

为什么仍在使用C?PDF格式

我会用谷歌搜索..因为网络上已经有很多评论


17
我用C编写了很多代码,然后用C ++做了很短的一段时间,然后用VB进行了一段令人尴尬的长时间,现在我在过去的几年中一直在使用C#。从那时起,我已经写了一些C和C ++代码,并且我意识到C是定义明确且紧密的C#是强大而强大的,而C ++很烂。
CMPalmer,2009年

25
Linus并不真正有资格谈论C ++的优点。夸他好像他是一个先知一样愚蠢。而“以艰难的方式做事”这一点没有道理。有充分的理由使用C,但是其中没有“更多的工作”或“ Linus这么说”。
jalf

8
@jalf并没有引用Linus的话,就好像他是某种oracle一样,它很好地提到了一位知名程序员在世界上最常用的程序之一:Linux内核中的选择。这个问题征求意见(为什么有人会选择C),这是我要回答的问题。
Ric东京2009年

6
Linus是C ++观点的不好来源,因为他不使用C ++,据我所知,他在1990年只尝试过一次。
Zan Lynx

3
@Zan Linus在其他地方展示了更多的自我控制能力:“我们希望使用C ++及其带来的额外功能,但是要比C语言更难理解C ++中的不良代码。” 我的回答中引用的是对观点的记录,而不是“跟随领导者”。
Ric东京2009年

26

因为他们在写插件,而C ++没有标准的ABI。


9
尽管确实如此,但坚持使用C并不是令人信服的理由,因为您可以使用C链接导出必要的函数,并且仍然将实现保留在C ++中。
codelogic

2
@codelogic-与等效的C项目相比,C ++项目倾向于导出更多类型和函数。可以将其隐藏在最终的共享库中,但是付出的努力可能超过其应得的价值。
汤姆

tbh不是一个很好的答案,而是+1,因为C ++没有标准的ABI(是的
。.C

6
C也没有标准的ABI。
斯蒂芬·佳能

25

较长的编译时间可能很烦人。使用C ++,您的编译时间可能会很长(当然,这意味着要花更多的时间进行堆栈溢出!)。


为什么这被否决了?我自己在C ++中做了很多工作,并且我不会再回到C上了,但是它确实会花费很长的编译时间(例如,考虑模板)。
弗兰克,

6
我使用C ++进行实际工作,但是由于几乎是即时的编译时间,所以我总是使用C进行原型设计。
汤姆

嗯,如果以正确的方式做,即没有we肿,我们可能需要这些#includes,但不能确定这是正确的,所以我将包括所有这些#包括编译时间都整齐。当我入侵一个或三个文件时,仅花1-2秒即可编译我的100个KLOC项目。
塞巴斯蒂安·马赫2014年

4
@Tom:我想知道您的实际工作C ++是什么样的,如果可以在C中进行原型制作。您是否未使用C ++的功能?你能详细说明吗?
塞巴斯蒂安·马赫2014年

24

我习惯将C ++用于我的项目。然后我得到一份使用纯C的工作(20年来不断发展的AV软件代码库,文档不完善...)。

我喜欢用C编写的三件事:

  • 没有什么隐含的内容:您可以看到您的程序确切执行或不执行的操作。这使调试更加容易。

  • 缺少名称空间和重载可能是一个优点:如果您想知道某个函数的调用位置,只需在源代码目录中进行grep,它就会告诉您。无需其他特殊工具。

  • 我重新发现了函数指针的功能。基本上,它们允许您执行在C ++中所做的所有多态操作,但是它们甚至更加灵活。


8
+1然而,C中的这种多态性通常是通过void *获得的,这很危险,因为它使编译器无法检查您是否正在做讨厌的事情。
gd1 2013年

4
@ gd1在实践中,我不记得有什么情况会void*引起麻烦。有许多防御性的编程技术可以防止错误:将断言放到任何地方,在您的结构中(在调试版本中)添加幻数,等等。但是如今,我们有valgrind博士。内存,甚至MSVC都使用代码来检测问题,因此很容易找出内存损坏问题。
Calmarius

4
我几乎从来没有在程序中遇到内存损坏的情况,但是如果可能的话,我希望在运行程序之前先检测出错误。强制void*转换whatever*为编译器真诚接受的东西。我更喜欢编译器不要相信我,并且可以执行健壮的类型检查。C ++编译器发出的模板替换错误很难读,但至少不能编译垃圾。
gd1 2013年

1
@ gd1回到您的第一条评论,我不知道您在程序技术方面有多少经验(我发现您在OO标签中很活跃)。在void*通常是可以避免的。添加自定义行为时的典型模式是传递函数指针和void*用于用户数据的。通用接口通常看起来像这样。然后,库在将其传递void*回您的回调时不对其进行任何其他处理。大多数情况下,您没有任何额外的数据,因此您传递NULL,并忽略回调中的user参数。我以为你知道这一点。
Calmarius 2013年

@Calmarius“大多数情况下,您没有任何额外的数据”->这实际上是多态的优势。绑定额外的数据很容易,而无需使用空指针。因此,您的借口基本上是“无论如何我都不会真正使用该功能”。
user2445507 '18

15

我很惊讶没有人提到图书馆。许多语言都可以链接到C库并调用C函数(包括带有外部“ C”的C ++)。C ++几乎是唯一可以使用C ++库的东西(定义为“一个库,它使用C语言中不在C语言中的功能(例如,重载函数,虚方法,重载运算符,...],并且不导出)通过外部“ C”'通过C兼容接口进行所有操作)。


1
不是这样;你可以为extern“C”或__cdecl你的功能,它们暴露于C.
Crashworks

很好,但是还可以使用其他哪些语言?
09年

2
C lib可以在更多地方工作。
09年

1
所有可以链接到C的
站点

2
互操作性问题的最明显原因是名称处理,我认为值得提出。
汤姆


12

因为他们想使用C99中没有C ++中等效项的功能。


但是,对C ++有用的C99功能并不像人们乍看的那么多。可变长度数组?C ++具有std :: vectors。支持复数/虚数?C ++具有模板化的复杂类型。类型通用数学函数?C ++重载了标准数学函数,从而导致相同的结果。

命名为初始值设定项?不在C ++中,但是有一种解决方法:

struct My_class_params {
    int i;
    long j;
    std::string name;

    My_class_params& set_i(int ii)
    {
        i = ii;
        return *this;
    }

    My_class_params& set_j(long jj)
    {
        j = jj;
        return *this;
    }


    template <typename STRING>
    My_class_params& set_name(STRING&& n)
    {
        name = std::forward<STRING>(n);
        return *this;
    }

    My_class_params()
    {
        // set defaults
    }
};

class My_class {
    My_class_params params;
  public:
    My_class(const My_class_params& p) : params(p) { }
    ...
};

这使您可以编写如下内容:

My_class mc(My_class_params().set_i(5).set_name("Me"));

听见,听见!每次我不得不使用C ++时,缺少命名的指定初始值设定项都会使我感到困惑。
迅速

2
我对初始化程序的要求是100%!!!
Maygarden法官09年

如果要在函数外部初始化全局结构(因此不能.set _ *()),则C ++会强制您使用未命名的初始化程序语法或为结构编写构造函数。我不喜欢这些选项。
ephemient '02

C99(GCC)中还有一些VLA比使用起来要容易得多std:vector
Vahid Amiri

10

因为对于许多编程任务,C更简单,而且足够好。尤其是在对轻量级实用程序进行编程时,我会觉得C ++希望我出于自身的考虑而构建优雅的超结构,而不是简单地编写代码。

OTOH,对于更复杂的项目,其优雅度提供了比自然地从键盘流出的更好的坚固结构严谨性。


8

C ++的大多数重要功能都以某种方式涉及类或模板。这些是很棒的功能,除了编译器将它们转换为目标代码的方式之外。大多数编译器使用名称修饰,而那些至少不做一些混乱的操作。

如果您的系统像许多应用程序一样独立运行,那么C ++是一个不错的选择。

如果您的系统需要与不是必须用C ++编写的软件进行交互(通常是在汇编器或Fortran库中),那么您将处于困境。要与这种情况进行交互,您需要禁用这些符号的名称修饰。这通常是通过声明那些对象来完成的extern "C",但是它们不能是模板,重载函数或类。如果这些很可能是您的应用程序API,则必须使用帮助程序功能将它们包装起来,并使这些功能与实际实现保持同步。

实际上,C ++语言为可以在纯C中轻松实现的功能提供了标准语法。

简而言之,对于大多数人来说,可互操作的C ++开销太大了。


3
我听到这让我感到非常震惊,因为我用C ++编写了很多具有外部“ C”接口的.DLL,因此可以从C或任何其他CLR语言中调用它们。当然,您不能简单地公开成员函数指针,但是对于__cdecl调用进行数据封送处理确实没有太大的麻烦。
Crashworks 2009年

1
实际上,您可以导出模板代码。它只需要为要使用的每种类型使用非模板函数包装器即可避免名称冲突。
Maygarden法官09年

8

这很肤浅,但是作为一个忙碌的学生,我选择了C,因为我认为C ++的学习时间会太长。我大学的许多教授都不会接受Python作业,我需要快速上手。


8
明智的老师!
Andrei Ciobanu 2010年

6

关于“只使用要使用的C ++的子集”的一句话:这个想法的问题是,强制项目中的每个人都使用相同的子集是有代价的。我个人的观点是,对于松散耦合的项目(例如,开源项目),这些成本相当高,而且C ++完全无法成为更好的C语言,因为无论您在哪里使用C语言,都无法使用C ++。


6

噢,我的C与C ++,这是开始一场火焰大战的好方法。:)

我认为C更适合驱动程序和嵌入式代码。

C ++具有C所没有的一些强大功能,但是当人们编写具有明显副作用的代码时,C ++的许多面向对象功能可能会造成巨大的代码混乱。疯狂的代码可以隐藏在构造函数,析构函数,虚函数中,... C代码的美在于该语言在背后没有任何明显的作用,因此您可以阅读代码,而不必查看每个构造函数和析构函数等等。许多问题是某些人的不良编码习惯。

我的理想语言是C99加上安全C ++功能的最小子集的组合,该功能会在二进制输出中增加零(或接近零)的编译器开销。完美的补充将是数据和函数的类封装和命名概念。


将其命名为C +或C100:_)
m3nda

4

关于为什么为什么要选择C而不是C ++,我还没有找到很多证据。

你几乎不能称呼我要说的证据。这只是我的意见。

人们喜欢C,因为它很好地适合了程序员的思想。

C ++有很多复杂的规则[什么时候需要虚拟析构函数,什么时候可以在构造函数中调用虚拟方法,重载和重载如何交互,...]并掌握它们全部需要花费很多精力。同样,在引用,运算符重载和函数重载之间,理解一段代码可能会要求您理解其他可能很难找到的代码。

为什么组织更喜欢C而不是C ++的另一个问题。我不知道,我只是一个人;-)

为了捍卫C ++,它的确为表带来了宝贵的功能。不过,我最重视的一种可能是参数('ish)多态:以一种或多种类型作为参数的操作和类型。


2
++score:您的陈述“人们喜欢C,因为它很适合程序员的思想”,这是一个非常好的陈述。能够使用一种简单的语言进行编程,在这种语言中,您所看到的就是所得到的,这对于编程语言来说是一个真正吸引人的特性。
tchrist

3

我想说C比C ++可以更好地控制优化和效率,因此在内存和其他资源有限且每次优化都有帮助的情况下很有用。当然,它的足迹也较小。


你能举一些例子吗?
安德鲁·格兰特

因此,与使用C ++编译器进行编译相比,使用C编译器进行编译的相同C代码会更有效?
Steve Kuo

1
几年前,Linux内核可以使用gcc或g ++进行编译,但是g ++创建的代码较慢(“最后,而Linus维护开发内核...”下的tux.org/lkml/#s15-3)。
Max Lybbert 09年

我想我在考虑可以控制更多代码如何通过C ++在C中进行优化的思路。就像使用汇编语言的程序员比使用高级语言的程序员如何更精确地微调其代码一样。
克里斯,

2

有些商店还采用类似C的方式使用某些 C ++功能的方法,但要避免使用那些令人反感的功能。例如,使用类和类方法以及函数重载(即使C语言顽固者通常也很容易应对),而STL,流运算符和Boost则不容易(它们较难学习并且具有不良的内存特性)。


1

因为您是在为资源紧张的系统(例如嵌入式系统或某种真正的裸机代码,例如内核)编写的,并且您希望尽可能少的开销。

大多数嵌入式系统没有C ++编译器是有原因的-并不是人们不想要这样的编译器,而是将C ++代码挤在一个很小的空间中几乎是不可能的任务。


3
C ++本身作为一种语言并没有多大问题,但是会导致随意使用模板的病态膨胀。
Crashworks

1
ecos主要用C ++编写。语言(与C相比)与可执行文件大小(只要您知道要使用的功能)之间没有关系。
user52875 '01

1
“只要您知道要使用什么功能”。这就是重点-说“好吧,我们有C ++,但由于开销原因,我们不能支持一半的语言功能”的结果是Symbian / C ++,它使C程序员 C ++程序员感到困惑和愤怒……
Steve Jessop

1
同意所有观点。我们“知道要​​使用哪些功能”的解决方案是只使用C编译器并每天调用它。当然,我们可以使C ++正常工作(以一种超级呆滞的方式真的很有趣),但是我们有产品要交付,并且没有时间担心它。
Electrons_Ahoy

1

C需要的是更好的预处理器。cfront是一个因此诞生的c ++

我将使用C,在这种情况下,“ c ++作为预处理程序”将不可行。

我很确定,在任何编写良好的c ++库/框架/工具包的底部,您会发现dirty-old-c(或静态强制转换,这是相同的)


0
  • 直到几年前,现有的C ++编译器都缺少重要功能,或者支持能力很差,而且所支持的功能在它们之间千差万别,因此很难编写可移植的应用程序。
  • 由于没有标准的符号命名,因此其他语言/应用程序很难直接支持C ++类。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.