知道C会让我用其他任何语言写出更好的代码是什么样的例子?

在Stack Overflow播客中,Joel Spolsky不断向Jeff Atwood讲述Jeff不知道如何用C编写代码的问题。他的声明是“知道C可以帮助你编写更好的代码。” 他还总是使用某种涉及字符串操作的故事,以及如何知道C将允许您用不同的语言编写更有效的字符串例程。

作为一个知道一点C但又喜欢用perl和其他高级语言编写代码的人,我从来没有遇到过我能够通过编写C来解决的问题。

我正在寻找实际情况的例子,在这些情况下,在用高级/动态语言(如perl或python)编写项目时,了解C会很有用。

编辑:阅读你们提交的一些答案很棒,但在这方面对我来说仍然没有任何意义:

以strcat为例。 在C中组合字符串有正确的方法和错误的方法。但为什么我(作为高级开发人员)认为我比Larry Wall聪明? 为什么语言设计者不会以正确的方式编写字符串操作代码?

Joel Spolsky使用的经典例子是滥用strcat和strlen ,并且总体上发现了“Shlemiel the painter”算法。

这并不是说你需要C来解决高级语言无法解决的问题,而是知道C井可以让你对所有那些语言层次下发生的事情有所了解,这些语言允许你编写更好的软件。 因为这样的透视图可以帮助您避免编写您不知道的代码,例如实际上是O(n ^ 2)。

编辑:基于评论的一些澄清。

知道C不是这种知识的先决条件,有很多方法可以获得相同的知识。

了解C也不能保证这些技能。 你可能精通C语言,但仍然用你触摸的其他语言编写可怕的,笨拙的,kludgy代码。

C是一种低级语言,但它仍然具有现代化的控制结构和function,因此您并不总是陷入繁琐的细节中。 如果没有掌握某些基本原理(例如内存管理和指针的细节),就很难熟练掌握C语言,掌握这些基础知识通常会在使用任何语言时获得丰厚的回报。

它总是关于基本面。

在许多追求以及软件工程中都是如此。 让最好的程序员变得最好的并不是秘密的咒语,而是更好地掌握基础知识。 经验表明,C的知识往往与掌握某些基本原则具有更高的相关性,而学习C往往是获取这些知识的更容易和更常见的途径之一。

假设学习C会以某种方式自动让您更好地理解低级编程问题,这是错误的。 在很多情况下,即使C太高,也无法让您对效率问题有充分的了解。

经典是i ++与++ i。 它被过度引用,所以也许大多数人都知道这两个操作之间的性能影响。 但学习C本身不会神奇地教你这个。

我想我理解有关字符串的论点。 当字符串操作看似简单时,人们经常以低效的方式使用它们。 但同样,知道strncat存在并不能让你充分了解效率问题。 许多C程序员可能甚至没有想过strncat必须在内部进行strlen操作。

即使使用C,如果效率受到关注,了解幕后发生的事情也很重要。 知道C的人往往会在一个进程中看待事物。 程序集和机器代码是C的构建块,而C是更高级语言的构建块。

这并不是特别正确,但很明显,C比许多更高级别的语言“更接近金属”。 这至少有两个影响:效率问题并不隐藏在隐式行为背后,而且更容易搞砸。

因此,您需要了解C如何为您提供优势的具体示例。 我不认为有一个。 我认为当他们说这是因为知道你正在编写的任何语言背后发生的事情时,人们的意思是帮助你做出更明智的决定如何编写代码。 但是,例如,假设C是“Java中幕后发生的事情”是错误的。

很难准确量化,但了解C将使您更深入地了解如何实现更高级别的语言结构,因此您将能够更好地以智能方式使用构造。

给你一个特定的理由:必须编写我自己的垃圾收集例程,这有助于我编写更好的代码。

我认为我从未发现过用高级语言无法解决的问题; 但是从学习C开始,它已经为我灌输了许多优秀的开发实践。 了解应用程序流程的基本部分如何工作将使您能够查看自己的代码并更好地了解数据如何流动以及数据的存储位置。 这样就可以更好地理解如何跟踪泄漏的内存,缓慢的磁盘读取,构造不良的缓存等。

跟踪指针…这是另一个浮现在脑海中的指针。

经典示例涉及较低级别的内存管理,例如链表类的实现:

struct Node { Data *data; Node *next; } 

了解指针如何用于迭代列表,以及它们在机器架构方面的含义将使您更好地理解高级代码。

Joel所指的另一个例子是字符串连接的实现,以及从一组数据创建字符串的正确方法。

 // this is efficient for (int i=0; i< n; i++) { strcat(str, data(i)); } // this could be too, but you'd need to look at the implementation to be sure std::string str; for (int i=0; i 

知道C可以帮助你在C中编写更好的代码。我想Joel Spolsky的例子在C ++或Objective-C中几乎没用,其中存在操作字符串的特定类,并且考虑到了性能。 此外,在其他语言中使用C技巧可能会更高效。

尽管如此,C知识对于理解其他语言中的一般概念以及在许多情况下引擎盖背后的内容非常有帮助。

作为一个知道一点C但又喜欢用perl和其他高级语言编写代码的人,我从来没有遇到过我能够通过编写C来解决的问题。

我正在寻找实际情况的例子,在这些情况下,在用高级/动态语言(如perl或python)编写项目时,了解C会很有用。

很容易开始编写高级代码,然后想知道它运行缓慢。 事实上,有很多方法可以编写perl或python代码,有些方法比其他代码更好(比更高效)。 如果您知道在perl或python中执行代码的低级细节(两者都是用C编写的),您可以编写几个低效的代码 – 比如知道哪个循环结构更快,内存如何保留/释放等等。

此外,在perl或python中编写项目时,有时会遇到性能问题。 该语言的创建者(至少Guido)主张您在C中实现该部分作为语言扩展。 要做到这一点,你必须要知道C.

所以,那里。

出于参数的目的,假设您想要将从1到n的所有整数的字符串表示连接起来(例如, n = 5将产生字符串“12345”)。 这就是人们如何在Java中天真地做到这一点。

 String result = ""; for (int i = 1; i <= n; i++) { result = result + Integer.toString(i); } 

如果你要在C语言中尽可能地重写那段代码段(在Java中非常好看),你会得到一些东西让大多数C程序员都害怕:

 char *result = malloc(1); *result = '\0'; for (int i = 1; i <= n; i++) { char *intStr = malloc(11); itoa(i, intStr, 10); char *tempStr = malloc(/* some large size */); strcpy(tempStr, result); strcat(tempStr, intStr); free(result); free(intStr); result = tempStr; } 

因为Java中的字符串是不可变的,所以Integer.toString创建一个虚拟字符串,字符串连接创建一个新的字符串实例,而不是改变旧的字符串实例。 仅仅查看Java代码就不容易看到了。 知道所述代码如何转换为C是一种了解所述代码的低效率的方法。

你使用数组吗? 你是否遇到过需要将项目存储在内存中的情况,而不知道有多少项目(即基于数据库中的查询?)然后我想C会教你很多东西,比如堆栈,结构和链接列表帮你。 此致,安迪

知道C真的不值得。 我们中许多认识C的人都非常喜欢认为所有深刻见解都是有价值和重要的。

我们中的一些人知道C不能想到C的一个特定function,这有助于了解。

知道指针在C中是如何工作的(尤其是使用C的语法)并不是那么有用。 在高级语言中,您的语句会创建对象并管理其交互。 从假设的角度来看,指针和参考文献可能是有趣的。 但是这些知识对如何使用Java或Python没有实际影响。

更高级的语言就是它们的方式。 知道如何不改变这些语言; 它不会改变您使用它们的方式,调试或测试它们。

了解如何创建或操作链表对Python列表类定义没有任何实际影响。 没有。

了解Linked List和Array List之间的区别可能有助于您编写Java程序。 但是C实现并没有帮助您在Linked List和Array List之间进行选择。 该决定独立于了解C.

每种语言都有不好的算法。 了解C的内在奥秘并不会使坏算法变坏。 了解C并不能帮助您了解Java集合或Python内置类型。

我在学习中看不出任何价值C.学习Fortran同样有价值。

我认为这样,所有内容都归结为跨平台级别的C,并以特定于平台的方式进行组装。 所以这就像是一个越野赛车拉力赛车,而C是基本的汽车机械师,你可以成为一名优秀的车手但是当你遇到麻烦时知道C意味着你可能会让自己重新参加比赛,如果不是你就会被称为机械师。 而assembly是机械师和制造商所知道的,如果这是你想做的事情,这是值得投资的,否则你就可以信任机械师。

具体考虑内存管理,硬件驱动程序,物理引擎,高性能3D图形,TCP堆栈,二进制协议,嵌入式软件,创建像Perl这样的高级语言

你不能在Perl中编写OS内核; C对于它来说是一个更好的选择,因为它足够低级,无法表达内核应该做的所有事情,并且足够便携,可以让你将内核移植到不同的架构

了解C并不是能够有效使用更高级语言的必要条件,但它肯定可以帮助人们对计算机和软件的工作原理有所了解 – 我认为它类似于了解某些汇编语言或计算机体系结构/硬件逻辑的断言(和/或/ nand gate等)可以帮助C程序员成为更好的程序员。

有时为了解决问题,有助于了解事情是如何“在你的”下面工作的。

我不认为这意味着程序员必须知道C才能成为一名优秀的程序员,但我认为知道C对几乎所有程序员都有帮助。

不太了解Perl,我想知道现在是否可以将处理器负载分配到多个物理内核,并在Perl的单个程序中创建多个线程,而不会产生额外的进程

我认为没有任何具体的例子。

学习C对你的作用是为你提供洞察力,拓宽思维,使计算机(和软件)如何运作。 这是一个非常抽象的事情..

它不会让你在python中编写更好的代码,它只会让你更像一个计算机科学家。

Wedge对Joel的文章提到画家Shlemiel的参考是一个有趣的,但在这里没有任何意义。 该算法不以任何特定方式与C相关联(尽管它以空终止字符串表示)。

Python的字符串无论如何都是不可变的,与C的字符串模型完全不同,所以我不太清楚这种关系。

我想一个具体的例子是优化解析器或词法分析器或一直保持写入字符串缓冲区的程序。 如果使用普通字符串而不是字符串缓冲区,则在构建非常大的字符串时会遇到问题。

考虑一下:

 a = a + b 

制作a和b的副本。 它不会更改a引用的字符串,它会创建一个新字符串,分配更多内存等。

如果a变得相当大,并且你不断添加小东西,那么画家Shlemiel将表现出来。

但话说回来,知道这与知道C无关,只知道你的语言如何在低级别实现。 (这是有经验的C将帮助你)。

从技术上讲,C的所有缺陷都会迫使你围绕它们进行编码; 让你写更多代码 – >让你更有经验。 例如,缺少任何大于32位的可移植整数,C在过去曾让我编写自己的bignum库。

缺少隐式内存,资源和错误管理(垃圾收集,RAII,自动调用构造函数/析构函数,可能是exception)会迫使C用户编写大量初始化,error handling和清理代码。 它可能只是我,但我从不厌倦编写这样的代码。 我去阅读我调用的每个外部函数的文档,返回到我的代码并检查每个返回值和其他失败指示的东西。 它甚至让我感到安全!

最后一点可能是支持这一论点的最大一点。 在开始分析每种语言中遇到的每个变量的生命周期之前,您只能编写这么多malloc()/ free()对! C ++的自动存储对象也无助于此类障碍。

编写真正可移植的C代码通常要求程序员不要对主机系统做出很多假设 – 想想sizeof(),CHAR___BITS,unsigned long,UINT_MAX。 虽然这并没有帮助我在其他语言中编写更好的代码,但它帮助我思考了可能的替代实现:微小的微处理器如何仍然可以运行我的C代码,为我的简单单行语句生成大量的RISC指令。 (这是另一回事;没有多少其他语言在我的头脑中很容易映射到给定的汇编语言。再说一遍,这可能只是我。)

当然,这些论点都不仅仅适用于C. @ S.Lott有一个有效的观点 – Fortran可能是一个同样好的选择。 但是有很多C代码! 从上到下的整个个人计算机系统 – 从库到驱动程序到内核的应用程序都可以在C语言的源代码中找到。如果你无法阅读它,那将是一种浪费。

在Python中,假设你有一个function

 def foo(l=[]) l.append("bar") return l; 

在某些版本的Python上,大约一年前可用,运行foo()一段时间,你会得到一个非常有趣的结果(即["bar","bar","bar","bar] )。

似乎有人将默认参数实现为静态变量(并且没有重置它),因此会发生意外结果。

也许我的例子是人为的 – 我的一个朋友,他真的喜欢Python,发现了这个奇怪的错误,但事实是所有这些语言都是用C或C ++实现的。 不了解和不理解对基础语言至关重要的概念意味着您将无法深入理解基于此构建的语言。

我发现所有“为什么要烦恼C / C ++ / ASM愚蠢”。 如果你足够倾向于学习一门语言,那就意味着你很好奇,首先要进入它。 为什么要在C之前停止?

知道C很棒,因为它背后没有任何作用(GC,边界检查等)。 它只会完全按照你的说法进行操作。 没有任何暗示。 即使是C ++,你也不会用RAII告诉它(当然,暗示对象在超出范围时会被破坏,但实际上并没有写出来)。 C是一种了解计算机“引擎盖下”内容的好方法,无需编写程序集。

低效的代码(例如,字符串+ =的循环)在任何语言中通常都是低效的。 如果有人解释为什么它在一种语言或另一种语言中效率低下,会有什么不同? 知道C,但没有意识到方法是低效的,与知道python并没有意识到相同没什么不同。

我认为值得了解一些低级语言,并且有选择C的实用理由:

  • 它是低级的,接近汇编程序
  • 它很普遍

理解整个堆栈很有价值。 有时你需要调试一些内容。 有时你不能在没有低级知识的情况下解决性能问题(通常情况并非如此,例如,当性能问题纯粹是算法时,但有时却是这样)。

为什么C被广泛认为是典型的“底层”,而不是其他一些语言? 我认为这是因为C是一种低级编程语言, C赢了 。 现在已经有一段时间了,但C并不总是占主导地位。 举一个着名的例子,Common Lisp的支持者(它有自己编写低级代码的方式)希望他们的语言也会受欢迎,最终会丢失 。

以下通常在C中实现:

  • 操作系统(Unix变种,Windows,许多嵌入式操作系统)
  • 更高级的编程语言(许多流行的Java,Python等实现)
  • (显然)大量的流行开源项目

我不是硬件用户,但我认为C也大大影响了CPU设计。

因此,如果你相信理解整个堆栈,那么从务实的角度来看,学习C是最好的选择。

作为一个警告,我认为值得学习汇编程序。 虽然C接近金属,但在我不得不做一些汇编之前,我并没有完全理解C. 偶尔有助于理解函数调用是如何实现的,如何for循环等等。不重要但也很有用的是必须(至少一次)处理没有虚拟内存的系统。 在Windows,Unix和某些其他操作系统上使用C时,即使是不起眼的malloc也会做很多工作,如果您不得不处理手动锁定和解锁内存,那么这些工作更容易理解,调试和/或调整地区(不是我建议定期这样做!)