在听StackOverflow播客的时候,经常有人说“真正的程序员”是用C语言编写的,而C语言的速度要快得多,因为它“接近机器”。把前面的断言留到另一篇文章,C有什么特别之处,使它比其他语言更快?或者换句话说:什么能阻止其他语言编译成二进制代码,使其运行速度与C语言一样快?
当前回答
原因有很多,包括:
它被编译成汇编语言。 它是静态类型的。 没有垃圾回收。 没有异常机制。 编译器优化 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语言没有这些,这意味着没有开销,但这意味着程序员需要能够分配内存并释放它们以防止内存泄漏,并且必须处理变量的静态类型。
也就是说,许多语言和平台,如Java(其Java虚拟机)和。net(其公共语言运行时),多年来通过即时编译(从字节码生成本机机器代码以实现更高性能)等技术改进了性能。
我在链接上找到了一个关于为什么有些语言更快,有些更慢的答案,我希望这将更清楚为什么C或c++比其他语言更快,还有一些其他语言也比C更快,但我们不能使用所有的语言。一些解释-
Fortran仍然重要的一个重要原因是它的速度快:用Fortran编写的数字处理例程往往比用大多数其他语言编写的等效例程要快。在这个领域与Fortran竞争的语言是C和c++,因为它们在性能上具有竞争力。
这就提出了一个问题:为什么?是什么让c++和Fortran速度如此之快?为什么它们比其他流行语言(如Java或Python)性能更好?
解释与编译 根据编程语言所鼓励的编程风格和所提供的特性,有许多方法可以对编程语言进行分类和定义。在性能方面,最大的区别是解释语言和编译语言之间的区别。
划分并不难;而是有一个光谱。在一端,我们有传统的编译语言,包括Fortran、C和c++。在这些语言中,有一个独立的编译阶段,将程序的源代码转换为处理器可以使用的可执行形式。
这个编译过程有几个步骤。对源代码进行分析和解析。基本的编码错误,如错字和拼写错误,此时可以检测到。解析后的代码用于生成内存中的表示,该表示也可用于检测错误——这一次是语义错误,例如调用不存在的函数,或者试图对文本字符串执行算术操作。
然后,这个内存中表示形式用于驱动代码生成器,即生成可执行代码的部分。代码优化,以提高所生成代码的性能,在此过程中的不同时间执行:可以在代码表示上执行高级优化,而在代码生成器的输出上使用低级优化。
实际执行代码发生在后面。整个编译过程只是用来创建可以执行的内容。
在另一端,我们有口译员。解释器将包括一个类似于编译器的解析阶段,但这随后用于驱动直接执行,程序立即运行。
最简单的解释器包含与该语言支持的各种特性相对应的可执行代码,因此它将具有用于添加数字、连接字符串以及给定语言所具有的任何其他功能的函数。当它解析代码时,它将查找相应的函数并执行它。在程序中创建的变量将保存在某种将其名称映射到其数据的查找表中。
解释器风格的最极端的例子是类似批处理文件或shell脚本的东西。在这些语言中,可执行代码通常甚至不内置在解释器本身中,而是单独的独立程序。
So why does this make a difference to performance? In general, each layer of indirection reduces performance. For example, the fastest way to add two numbers is to have both of those numbers in registers in the processor, and to use the processor's add instruction. That's what compiled programs can do; they can put variables into registers and take advantage of processor instructions. But in interpreted programs, that same addition might require two lookups in a table of variables to fetch the values to add, then calling a function to perform the addition. That function may very well use the same processor instruction as the compiled program uses to perform the actual addition, but all the extra work before the instruction can actually be used makes things slower.
如果你想知道更多,请查看来源
甚至C和c++之间的差异有时也会很大。
当你为一个对象分配内存,调用构造函数,在字边界上对齐内存等等,程序最终会经历很多开销,这些开销都是从程序员那里抽象出来的。
C迫使您查看程序所做的每一件事,通常是非常精细的细节。这使得编写执行大量与当前目标无关的任务的代码变得更加困难(尽管并非完全不可能)。
因此,例如在BASIC程序中,你可以使用INPUT关键字从STDIN读取字符串并自动为其变量分配内存,在C中,程序员通常已经分配了内存,并可以控制诸如程序是否阻塞I/O,以及它是否在获得所需信息后停止读取输入或继续读取字符到行尾等事情。
C also performs a lot less error-checking than other languages, presuming the programmer knows what they're doing. So whereas in PHP if you declare a string $myStr = getInput(); and go on to reference $myStr[20], but the input was only 10 characters long, PHP will catch this and safely return to you a blank string. C assumes that you've either allocated enough memory to hold data past the end of the string or that you know what information comes after the string and are trying to reference that instead. These small factors have a huge impact on overhead in aggregate.