在听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快,其他语言中的算法或设计模式的一些实现可能比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语言构建的程序只需要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程序员必须对每几行代码做出这类低级决策。它加起来就是一个手工制作、手工优化的可执行文件。
C的设计者们已经做出了取舍。也就是说,他们决定把速度放在安全之上。C不会
检查数组下标边界 检查未初始化的变量值 检查内存泄漏 检查空指针解引用
当你索引到一个数组时,在Java中,它接受虚拟机中的一些方法调用,绑定检查和其他健全检查。这是有效的,绝对没问题,因为它在应有的地方增加了安全性。但是在C语言中,即使是非常微不足道的东西也不会被放在安全的地方。例如,C不要求memcpy检查要复制的区域是否重叠。它并不是一种用于编写大型商业应用程序的语言。
但是这些设计决策并不是C语言中的bug。它们是被设计出来的,因为它允许编译器和库编写者从计算机中获得每一点性能。下面是C语言的精神——C语言的基本原理文档是这样解释的:
C code can be non-portable. Although it strove to give programmers the opportunity to write truly portable programs, the Committee did not want to force programmers into writing portably, to preclude the use of C as a ``high-level assembler'': the ability to write machine-specific code is one of the strengths of C. Keep the spirit of C. The Committee kept as a major goal to preserve the traditional spirit of C. There are many facets of the spirit of C, but the essence is a community sentiment of the underlying principles upon which the C language is based. Some of the facets of the spirit of C can be summarized in phrases like Trust the programmer. Don't prevent the programmer from doing what needs to be done. Keep the language small and simple. Provide only one way to do an operation. Make it fast, even if it is not guaranteed to be portable. The last proverb needs a little explanation. The potential for efficient code generation is one of the most important strengths of C. To help ensure that no code explosion occurs for what appears to be a very simple operation, many operations are defined to be how the target machine's hardware does it rather than by a general abstract rule. An example of this willingness to live with what the machine does can be seen in the rules that govern the widening of char objects for use in expressions: whether the values of char objects widen to signed or unsigned quantities typically depends on which byte operation is more efficient on the target machine.
推荐文章
- 如何找到Java堆大小和内存使用(Linux)?
- 如何在HTML5中改变视频的播放速度?
- 我如何提高ASP。NET MVC应用程序性能?
- C多行宏:do/while(0) vs作用域块
- time_t最终的类型定义是什么?
- 我需要显式处理负数或零时,总和平方数字?
- 列表推导式和函数式函数比for循环更快吗?
- 函数名周围的括号是什么意思?
- 用C语言创建自己的头文件
- 格式化IO函数(*printf / *scanf)中的转换说明符%i和%d之间的区别是什么?
- main()中的Return语句vs exit()
- 如果不是内存地址,C指针到底是什么?
- 我如何在Visual Studio中预处理后看到C/ c++源文件?
- Pandas loc vs iloc vs at vs iat?
- 当WebSockets可用时,为什么要使用AJAX ?