在听StackOverflow播客的时候,经常有人说“真正的程序员”是用C语言编写的,而C语言的速度要快得多,因为它“接近机器”。把前面的断言留到另一篇文章,C有什么特别之处,使它比其他语言更快?或者换句话说:什么能阻止其他语言编译成二进制代码,使其运行速度与C语言一样快?
当前回答
撇开诸如热点优化、预编译元算法和各种形式的并行等高级优化技术不提,语言的基本速度与支持通常在内部循环中指定的操作所需的隐含的幕后复杂性密切相关。
也许最明显的方法是对间接内存引用进行有效性检查——比如检查指针是否为空,检查索引是否符合数组边界。大多数高级语言隐式地执行这些检查,但C不这样做。然而,这并不一定是这些其他语言的基本限制——一个足够聪明的编译器可能能够通过某种形式的循环不变代码运动,从算法的内部循环中删除这些检查。
C语言(在类似程度上与c++密切相关)更基本的优势是严重依赖基于堆栈的内存分配,这本质上是快速的分配、回收和访问。在C(和c++)中,主调用堆栈可用于分配原语、数组和聚合(结构/类)。
虽然C语言确实提供了动态分配任意大小和生命周期的内存的能力(使用所谓的“堆”),但默认情况下是避免这样做的(而是使用堆栈)。
诱人的是,有时可以在其他编程语言的运行时环境中复制C内存分配策略。asm.js已经证明了这一点,它允许用C或c++编写的代码被翻译成JavaScript的子集,并以接近本机的速度安全地运行在web浏览器环境中。
As somewhat of an aside, another area where C and C++ outshine most other languages for speed is the ability to seamlessly integrate with native machine instruction sets. A notable example of this is the (compiler and platform dependent) availability of SIMD intrinsics which support the construction of custom algorithms that take advantage of the now nearly ubiquitous parallel processing hardware -- while still utilizing the data allocation abstractions provided by the language (lower-level register allocation is managed by the compiler).
其他回答
令人惊讶的是,“C/ c++必须比Java快,因为Java是解释性的”的神话仍然活跃。有几年前的文章,也有最近的文章,用概念或测量来解释为什么这种情况并不总是如此。
当前的虚拟机实现(顺便说一下,不仅仅是JVM)可以利用程序执行期间收集的信息来动态地优化代码,使用各种技术:
将频繁的方法呈现给机器代码, 内联小方法, 锁紧调整
以及各种其他调整,这些调整是基于了解代码实际在做什么,以及它运行的环境的实际特征。
有什么能阻止其他语言 能够编译成二进制文件 运行速度和C一样快?
没什么。像Java或。net语言这样的现代语言更多地面向程序员的生产力,而不是性能。现在硬件很便宜。此外,编译到中间表示提供了很多好处,如安全性,可移植性等。net CLR可以利用不同的硬件-例如,你不需要手动优化/重新编译程序来使用SSE指令集。
c语言并没有什么特别之处,这也是它速度快的原因之一。
新语言支持垃圾收集、动态类型和其他功能,使程序员更容易编写程序。
问题在于,会有额外的处理开销,这会降低应用程序的性能。C语言没有这些,这意味着没有开销,但这意味着程序员需要能够分配内存并释放它们以防止内存泄漏,并且必须处理变量的静态类型。
也就是说,许多语言和平台,如Java(其Java虚拟机)和。net(其公共语言运行时),多年来通过即时编译(从字节码生成本机机器代码以实现更高性能)等技术改进了性能。
我知道很多人都说过这句话,但是:
C更快,因为它(为你)做的更少。
如果你花了一个月的时间用C语言构建的程序只需要0.05秒,而我花了一天的时间用Java写同样的程序,只需要0.10秒,那么C语言真的更快吗?
但是回答你的问题,编写良好的C代码通常会比其他语言编写的代码运行得更快,因为编写良好的C代码的一部分包括在接近机器的级别上进行手动优化。
尽管编译器确实非常聪明,但它们还不能创造性地提出与手工按摩算法竞争的代码(假设“手”属于一个优秀的C程序员)。
编辑:
很多评论都是这样的:“我用C语言编写,我不考虑优化。”
举个具体的例子:
在Delphi中我可以这样写:
function RemoveAllAFromB(a, b: string): string;
var
before, after :string;
begin
Result := b;
if 0 < Pos(a,b) then begin
before := Copy(b,1,Pos(a,b)-Length(a));
after := Copy(b,Pos(a,b)+Length(a),Length(b));
Result := before + after;
Result := RemoveAllAFromB(a,Result); //recursive
end;
end;
用C语言写:
char *s1, *s2, *result; /* original strings and the result string */
int len1, len2; /* lengths of the strings */
for (i = 0; i < len1; i++) {
for (j = 0; j < len2; j++) {
if (s1[i] == s2[j]) {
break;
}
}
if (j == len2) { /* s1[i] is not found in s2 */
*result = s1[i];
result++; /* assuming your result array is long enough */
}
}
但是C版本中有多少优化呢?我们在实现方面做了很多我在Delphi版本中没有考虑到的决定。字符串是如何实现的?在特尔斐我看不出来。在C语言中,我已经决定它将是一个指向ASCII整数数组的指针,我们称之为字符。在C语言中,我们每次测试一个字符的存在性。在Delphi中,我使用Pos。
这只是一个小例子。在一个大型程序中,C程序员必须对每几行代码做出这类低级决策。它加起来就是一个手工制作、手工优化的可执行文件。
推荐文章
- 如何有效地从数组列表或字符串数组中删除所有空元素?
- 在SQL Server上使用varchar(MAX) vs TEXT
- c++中size_t和int的区别是什么?
- .toArray(new MyClass[0]) or .toArray(new MyClass[myList.size()])?
- 在C和c++中静态变量存储在哪里?
- 是什么导致JNI调用变慢?
- 检查属性是否有属性
- errno线程安全吗?
- 如何快速清除JavaScript对象?
- 如何在C程序中获取当前目录?
- 互斥实例/教程?
- 如何添加一个'或'条件在#ifdef
- extern关键字对C函数的影响
- Node.js vs .Net性能
- 如果使用if-return-return或if-else-return?