在听StackOverflow播客的时候,经常有人说“真正的程序员”是用C语言编写的,而C语言的速度要快得多,因为它“接近机器”。把前面的断言留到另一篇文章,C有什么特别之处,使它比其他语言更快?或者换句话说:什么能阻止其他语言编译成二进制代码,使其运行速度与C语言一样快?


当前回答

我猜你忘了汇编语言也是一种语言:)

但是说真的,只有当程序员知道自己在做什么的时候,C程序才会更快。你可以很容易地编写一个C程序,它比用其他语言编写的程序运行得更慢。

C语言之所以更快,是因为它就是这样设计的。它允许你做很多“低级”的事情,帮助编译器优化代码。或者,我们可以说,你程序员负责优化代码。但这通常相当棘手,而且容易出错。

其他语言,就像前面提到的其他语言一样,更关注程序员的生产力。人们普遍认为程序员的时间比机器的时间要昂贵得多(即使在过去)。因此,尽量减少程序员花在编写和调试程序上的时间,而不是减少程序的运行时间,是很有意义的。为了做到这一点,您将牺牲一些可以使程序更快的事情,因为许多事情都是自动化的。

其他回答

这些答案中的许多都给出了为什么C更快或更快的有效理由(无论是在一般情况下还是在特定的场景中)。不可否认的是:

Many other languages provide automatic features that we take for granted. Bounds checking, run-time type checking, and automatic memory management, for example, don't come for free. There is at least some cost associated with these features, which we may not think about—or even realize—while writing code that uses these features. The step from source to machine is often not as direct in other languages as it is in C. OTOH, to say that compiled C code executes faster than other code written in other languages is a generalization that isn't always true. Counter-examples are easy to find (or contrive).

尽管如此,我还是注意到另一件事,我认为它比其他任何因素都更能影响C与许多其他语言的比较性能。即:

其他语言通常更容易编写执行较慢的代码。通常,它甚至受到该语言的设计哲学的鼓励。推论:C程序员更有可能编写不执行不必要操作的代码。

例如,考虑一个简单的Windows程序,其中创建了一个主窗口。C版本将填充一个WNDCLASS[EX]结构,该结构将传递给RegisterClass[EX],然后调用CreateWindow[EX]并进入消息循环。以下是高度简化和缩写的代码:

WNDCLASS wc;
MSG      msg;

wc.style         = 0;
wc.lpfnWndProc   = &WndProc;
wc.cbClsExtra    = 0;
wc.cbWndExtra    = 0;
wc.hInstance     = hInstance;
wc.hIcon         = NULL;
wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName  = NULL;
wc.lpszClassName = "MainWndCls";

RegisterClass(&wc);

CreateWindow("MainWndCls", "", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
             CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

while(GetMessage(&msg, NULL, 0, 0)){
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

c#中类似的程序可能只有一行代码:

Application.Run(new Form());

这一行代码提供了近20行C代码所提供的所有功能,并添加了一些我们遗漏的功能,例如错误检查。这个更丰富、更完整的库(与典型C项目中使用的库相比)为我们做了很多工作,解放了我们的时间来编写更多的代码片段,这些代码对我们来说很短,但涉及到幕后的许多步骤。

但是,一个丰富的库使简单快速的代码膨胀并不是我真正想要的。当您开始检查我们的小一行程序实际执行时实际发生了什么时,我的观点就更加明显了。为了好玩,可以在Visual Studio 2008或更高版本中启用. net源代码访问,然后进入上面简单的一行代码。您将遇到的一个有趣的小珍宝是Control的getter中的这个注释。CreateParams:

// In a typical control this is accessed ten times to create and show a control.
// It is a net memory savings, then, to maintain a copy on control.
// 
if (createParams == null) {
    createParams = new CreateParams(); 
} 

十次。信息大致相当于存储在WNDCLASSEX结构中的内容和传递给CreateWindowEx的内容的总和,在它存储在WNDCLASSEX结构中并传递给RegisterClassEx和CreateWindowEx之前,从Control类中检索10次。

总而言之,在c#中执行这个非常基本的任务的指令数量比在C中多2-3个数量级,部分原因是使用了功能丰富的库,这是必然的,而我们简单的C代码只做了我们需要的事情,仅此而已。但部分原因是. net框架的模块化、面向对象的特性导致了大量的重复执行,而过程方法通常可以避免这些重复执行。

我并不是要挑c#或。net框架。我也不是说模块化、泛化、库/语言特性、OOP等等都是不好的东西。我曾经用C语言进行大部分开发,后来用c++,最近用c#。类似地,在使用C之前,我主要使用汇编。我的语言每“提高”一步,我就能在更短的时间内写出更好、更可维护、更健壮的程序。然而,它们的执行速度往往要慢一些。

这不是语言的问题,而是工具和库的问题。C语言可用的库和编译器比新语言要老得多。你可能认为这会让它们变慢,但事实恰恰相反。

这些库是在处理能力和内存非常重要的时候编写的。它们必须写得非常高效,才能发挥作用。C编译器的开发人员也花了很长时间为不同的处理器进行各种巧妙的优化。C语言的成熟和广泛采用使得它比同时期的其他语言具有显著的优势。它还使C语言在速度上比那些不像C语言那样强调原始性能的新工具更有优势。

只需在您的IDE中逐步检查机器代码,您就会看到为什么它更快(如果它更快的话)。它省去了很多手把手的环节。很有可能你的Cxx也会被告知不要使用,在这种情况下,它应该是相同的。

编译器优化被高估了,就像几乎所有关于语言速度的看法一样。

优化生成的代码只会对热点代码产生影响,也就是说,没有函数调用(显式或隐式)的紧凑算法。在其他地方,收效甚微。

c++的平均速度更快(就像它最初一样,主要是C的超集,尽管有一些不同)。然而,对于特定的基准测试,通常有另一种更快的语言。

https://benchmarksgame-team.pages.debian.net/benchmarksgame/

fannjuch-redux是Scala中最快的

n-body和fasta在Ada中更快。

频谱范数在Fortran中是最快的。

反补、mandelbrot和pidigits在ATS中最快。

regex-dna是JavaScript中最快的。

chameneau -redux最快的是Java 7。

Haskell的螺纹环速度最快。

其余的基准测试在C或c++中是最快的。

不要轻信别人的话,看看在代码的任何性能关键部分,C语言和你选择的语言的反汇编。我认为你可以在Visual Studio运行时的反汇编窗口中看到已分解的. net。如果Java使用windbg有点棘手,应该是可能的,尽管如果你用。net来做,许多问题将是相同的。

如果没有必要的话,我不喜欢用C来编写,但我认为,这些回答中吹捧除C之外其他语言的速度的许多主张可以放在一边,只需用C和您选择的高级语言分解相同的例程,特别是如果涉及大量数据(这在性能关键型应用程序中很常见)。Fortran在其专业领域可能是个例外,不知道。它比C高吗?

第一次比较JITed代码和本地代码时,我解决了。net代码是否能与C代码运行得相当的所有问题。额外的抽象层次和所有的安全检查都带来了巨大的成本。同样的成本可能也适用于Java,但不要相信我的话,在性能至关重要的地方尝试一下。(有没有人足够了解JITed Java来在内存中找到一个编译过的过程?这当然是可能的)