Quel est un exemple dans lequel connaître C me fera écrire un meilleur code dans n’importe quelle autre langue?

Dans les podcasts Stack Overflow, Joel Spolsky parle constamment à Jeff Atwood de Jeff ne sachant pas écrire du code en C. Son affirmation est que “connaître le C vous aide à écrire un meilleur code”. Il utilise également toujours une sorte d’histoire impliquant une manipulation de chaîne et explique comment la connaissance de C vous permettrait d’écrire des routines de chaîne plus efficaces dans un langage différent.

Connaissant un peu le C, mais aimant écrire du code en perl et dans d’autres langages de haut niveau, je n’ai jamais rencontré un problème que j’ai pu résoudre en écrivant le C.

Je cherche des exemples de situations réelles où la connaissance de C serait utile lors de la rédaction d’un projet dans un langage de haut niveau / dynamic comme perl ou python.

Edit: La lecture de certaines des réponses que vous avez fournies a été excellente, mais n’a toujours aucun sens pour moi à cet égard:

Prenons l’exemple strcat. Il existe un bon et un mauvais moyen de combiner des chaînes en C. Mais pourquoi devrais-je (en tant que développeur de haut niveau) penser que je suis plus intelligent que Larry Wall? Pourquoi les concepteurs de langage n’écriraient-ils pas le code de manipulation de chaîne correctement?

L’exemple classique utilisé par Joel Spolsky concerne l’ utilisation abusive de strcat et strlen et la découverte des algorithmes de “Shlemiel le peintre” en général.

Ce n’est pas que vous ayez besoin de C pour résoudre des problèmes que les langages de haut niveau ne peuvent pas résoudre, mais bien, savoir que C vous donne une perspective de ce qui se passe sous tous ces langages vous permet d’écrire de meilleurs logiciels. Parce qu’une telle perspective vous permet d’éviter d’écrire du code qui, à votre insu, est en fait O (n ^ 2), par exemple.

Edit: Quelques éclaircissements basés sur les commentaires.

Sachant que C n’est pas une condition préalable à une telle connaissance, il existe de nombreuses manières d’acquérir la même connaissance.

Connaître C n’est pas non plus une garantie de ces compétences. Vous maîsortingsez peut-être bien le langage C tout en écrivant un code horrible et minable dans toutes les autres langues que vous touchez.

C est un langage de bas niveau, mais il a toujours des structures de contrôle et des fonctions modernes, vous évitant ainsi de vous perdre dans les moindres détails. Il est très difficile de maîsortingser C sans acquérir une maîsortingse de certains principes fondamentaux (tels que les détails de la gestion de la mémoire et des pointeurs), dont la maîsortingse rapporte souvent de riches dividendes dans toutes les langues.

C’est toujours sur les fondamentaux.

Cela est vrai dans de nombreux domaines ainsi que dans le génie logiciel. Ce ne sont pas des incantations secrètes qui font les meilleurs programmeurs les meilleurs, mais bien une plus grande maîsortingse des principes fondamentaux. L’expérience a montré que la connaissance du C tend à avoir une plus grande corrélation avec la maîsortingse de certains de ces fondamentaux, et que l’apprentissage du C tend à être l’un des moyens les plus faciles et les plus courants d’acquérir de telles connaissances.

C’est une erreur de supposer que l’apprentissage C vous donnera automatiquement une meilleure compréhension des problèmes de programmation de bas niveau. Dans de nombreux cas, même le niveau C est trop élevé pour vous donner une bonne compréhension des problèmes d’efficacité.

Un classique est i ++ versus ++ i. C’est trop cité, alors peut-être que la plupart des gens connaissent les implications sur les performances entre ces deux opérations. Mais apprendre que C ne vous l’enseignerait pas comme par magie.

Je suppose que je comprends les arguments concernant les chaînes. Lorsque les opérations sur les chaînes sont simplifiées de manière trompeuse, les utilisateurs les utilisent souvent de manière inefficace. Mais une fois encore, le fait de savoir que strncat existe ne vous donne pas une idée complète des problèmes d’efficacité. Beaucoup de programmeurs C n’ont probablement même pas pensé au fait que strncat doit effectuer une opération strlen en interne.

Même en utilisant le C, il est important de comprendre ce qui se passe dans les coulisses si l’efficacité est une préoccupation. Les personnes qui connaissent C ont tendance à voir les choses dans une progression. Le code assembleur et le code machine sont les éléments constitutifs de C, tandis que C est un élément constitutif des langages de niveau supérieur.

Ce n’est pas particulièrement vrai, mais il est évident que C est “plus proche du métal” que de nombreux langages de niveau supérieur. Cela a au moins deux effets: les problèmes d’efficacité ne sont pas aussi cachés derrière un comportement implicite et il est plus facile de tout gâcher.

Donc, vous voulez un exemple spécifique de la façon dont connaître C vous donne un avantage. Je ne pense pas qu’il y en a un. Je pense que ce que les gens veulent dire en disant cela, c’est que savoir ce qui se passe dans les coulisses, quelle que soit la langue dans laquelle vous écrivez, vous aide à prendre des décisions plus intelligentes quant à la manière d’écrire du code. Cependant, c’est une erreur de supposer que C est “ce qui se passe dans les coulisses” en Java, par exemple.

Il est difficile de quantifier exactement, mais une compréhension de C vous donnera une meilleure idée de la façon dont les constructions de langage de niveau supérieur sont mises en œuvre. Par conséquent, vous serez mieux en mesure d’utiliser les constructions de manière intelligente.

Pour vous donner une raison spécifique: avoir à écrire mes propres routines de récupération de place m’a aidé à écrire un meilleur code.

Je ne pense pas avoir jamais trouvé un problème que je n’ai pas pu résoudre avec un langage de niveau supérieur; mais a commencé par l’apprentissage du langage C, il m’a inculqué un certain nombre d’excellentes pratiques de développement. En sachant comment les parties rudimentaires du stream d’une application fonctionnent, vous pourrez examiner votre propre code et obtenir un bon aperçu de la manière dont les données sont stockées et où elles sont stockées. Cela permet ensuite de mieux comprendre comment localiser les memory leaks, les lectures de disque lentes, les caches mal construits, etc.

Garder une trace de pointeurs … c’est un autre qui me vient à l’esprit.

Les exemples classiques concernent la gestion de la mémoire de niveau inférieur, telle que la mise en œuvre d’une classe de liste liée:

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

Comprendre comment les pointeurs sont utilisés pour parcourir la liste et ce qu’ils signifient en termes d’architecture de machine vous permettra de mieux comprendre votre code de haut niveau.

Joel faisait référence à un autre exemple: la mise en œuvre de la concaténation de chaînes et la bonne façon de créer une chaîne à partir d’un dataset.

 // 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 

Connaître C vous aide à écrire un meilleur code en C. Je suppose que l’exemple de Joel Spolsky est peu utile en C ++ ou en Objective-C où des classes spécifiques pour manipuler des chaînes existent et ont été conçues pour la performance. De plus, utiliser les astuces de C dans d’autres langues peut s’avérer très productif.

Néanmoins, la connaissance du langage C est très utile pour comprendre les concepts généraux dans d’autres langues et ce qui se cache derrière de nombreuses situations.

Connaissant un peu le C, mais aimant écrire du code en perl et dans d’autres langages de haut niveau, je n’ai jamais rencontré un problème que j’ai pu résoudre en écrivant le C.

Je cherche des exemples de situations réelles où la connaissance de C serait utile lors de la rédaction d’un projet dans un langage de haut niveau / dynamic tel que perl ou python.

Il est facile de commencer à écrire du code de haut niveau, puis nous nous demandons que cela fonctionne lentement. La vérité est qu’il existe de nombreuses façons d’écrire du code Perl ou Python, et que certaines sont meilleures (comme plus efficaces) que d’autres. Si vous connaissez les détails de bas niveau de la façon dont votre code est exécuté en perl ou en python (les deux étant écrits en C), vous pouvez coder plusieurs inefficacités – comme savoir quelle construction en boucle est la plus rapide, comment la mémoire est conservée / libérée, etc. .

De même, lorsque vous écrivez un projet en Perl ou en Python, vous heurtez parfois un mur de performances. Les créateurs du langage (Guido, au moins) recommandent que vous implémentiez cette partie en C, en tant qu’extension du langage. Pour ce faire, vous devrez connaître C.

Donc là.

Pour les besoins de l’argument, supposons que vous vouliez concaténer les représentations sous forme de chaîne de tous les entiers de 1 à n (par exemple, n = 5 produirait la chaîne “12345”). Voici comment on pourrait faire cela naïvement dans, disons, Java.

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

Si vous deviez réécrire le segment de code (ce qui est plutôt beau en Java) en C aussi littéralement que possible, vous auriez quelque chose à faire craindre la plupart des programmeurs 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; } 

Comme les chaînes en Java sont immuables, Integer.toSsortingng crée une chaîne factice et la concaténation de chaînes crée une nouvelle instance de chaîne au lieu de modifier l'ancienne. Ce n'est pas facile à voir en regardant simplement le code Java. Savoir comment ce code se traduit en C est un moyen d'apprendre exactement à quel point ledit code est inefficace.

Utilisez-vous beaucoup les tableaux? et rencontrez-vous des situations dans lesquelles vous avez besoin que des éléments soient stockés en mémoire sans connaître le nombre d’entre eux (c’est-à-dire basés sur une requête de la firebase database?), alors je suppose que C vous apprendrait de grandes choses comme des stacks, des structures et des listes de liens T’aider. Cordialement, Andy

Connaître C ne vaut vraiment pas grand chose. Beaucoup d’entre nous qui connaissent C aiment profondément penser que toutes ces idées profondes sont précieuses et importantes.

Certains d’entre nous qui connaissent C ne peuvent penser à une seule caractéristique spécifique de C qu’il serait utile de connaître.

Il n’est pas utile de savoir comment les pointeurs fonctionnent en C (en particulier avec la syntaxe de C). Dans un langage de haut niveau, vos instructions créent des objects et gèrent leur interaction. Les pointeurs et les références sont – peut-être – intéressants d’un sharepoint vue hypothétique. Mais la connaissance n’a aucun impact pratique sur la façon dont vous utilisez Java ou Python.

Les langues de niveau supérieur sont ce qu’elles sont. Savoir comment ne change pas ces langues; cela ne change pas la façon dont vous les utilisez, les corrigez ou les testez.

Savoir créer ou manipuler une liste liée n’a aucun impact terrestre sur la définition de classe de liste Python. Aucun.

Connaître la différence entre une liste liée et une liste de masortingces peut vous aider à écrire un programme Java. Mais l’implémentation C ne vous aide pas à choisir entre la liste liée et la liste de masortingces. La décision est indépendante de savoir C.

Un mauvais algorithme est mauvais dans toutes les langues. Connaître les mystères intérieurs de C ne rend pas moins mauvais un algorithme. Connaître C ne vous aide pas à connaître les collections Java ou les types intégrés Python.

Apprendre que C. Apprendre Fortran est tout aussi utile.

Je le vois comme ça, tout se résume à C dans un niveau multiplateforme et à un assemblage spécifique à une plate-forme. Donc, c’est comme être un coureur de rallye cross-country, et C est une mécanique de base de l’automobile, vous pouvez être un grand pilote, mais quand vous avez des problèmes, sachant que C signifie que vous pouvez probablement vous remettre dans la course, sinon vous êtes coincé à appeler la mécanique. . Et l’assemblage est ce que les mécaniciens et les fabricants savent, c’est un investissement rentable si c’est ce que vous voulez faire, sinon vous pouvez simplement faire confiance aux mécaniciens.

Pour des informations spécifiques, pensez à la gestion de la mémoire, aux pilotes matériels, aux moteurs physiques, aux graphiques 3D hautes performances, aux stacks TCP, aux protocoles binarys, aux logiciels intégrés, à la création de langages de haut niveau tels que Perl.

Vous ne pouvez pas écrire un kernel de système d’exploitation en Perl; C serait un bien meilleur choix pour cela, car il est assez bas pour exprimer tout ce que le kernel doit faire, et assez portable pour vous permettre de porter votre kernel à différentes architectures

Connaître C n’est pas une exigence pour pouvoir utiliser efficacement des langages de haut niveau, mais cela peut certainement aider les utilisateurs à comprendre le fonctionnement des ordinateurs et des logiciels – je pense que cela ressemble à une affirmation selon laquelle connaître un langage d’assemblage ou une logique architecturale / matérielle (et / ou / nand gates, etc.) peut aider un programmeur C à devenir un meilleur programmeur.

Parfois, pour résoudre un problème, il est utile de savoir comment les choses fonctionnent “en dessous” de ce que vous faites.

Je ne pense pas que cela signifie qu’un programmeur doit connaître C pour être un bon programmeur, mais je pense que connaître C peut être utile à presque tous les programmeurs.

Ne connaissant pas bien Perl, je me demande s’il est maintenant possible de répartir la charge du processeur sur plusieurs cœurs physiques avec plusieurs threads créés dans un même programme en Perl, sans générer de processus supplémentaires.

Je ne pense pas qu’il puisse y avoir aucun exemple spécifique.

Ce que l’apprentissage C fait pour vous, c’est vous donner un aperçu, un élargissement de l’esprit, du fonctionnement des ordinateurs (et des logiciels). C’est une chose très abstraite ..

Cela ne vous oblige pas à écrire un meilleur code en python, cela vous fait plutôt devenir un informaticien.

La référence faite par Wedge à l’article de Joel mentionnant Shlemiel le peintre est intéressante mais n’a aucune pertinence ici. Cet algorithme n’est pas lié à C de manière particulière (bien qu’il se manifeste par des chaînes terminées par un caractère nul).

Les chaînes de Python sont immuables de toute façon, et complètement différentes du modèle de chaînes de C, je ne vois donc pas très bien la relation.

Je suppose qu’un exemple concret est l’optimisation d’un parsingur syntaxique ou d’un lexer ou d’un programme qui écrit en permanence dans un tampon de chaîne. Si vous utilisez des chaînes normales au lieu d’un tampon de chaîne, vous rencontrerez un problème lorsque vous créez des chaînes très volumineuses.

Considérez que:

 a = a + b 

fait une copie des deux a et b . Cela ne change pas la chaîne qui a été référencée par un, il crée une nouvelle chaîne, alloue plus de mémoire, etc.

Si a devient considérablement volumineux et que vous continuez à y append de petites choses, le peintre Shlemiel se manifestera.

Mais là encore, savoir que cela n’a rien à voir avec C, mais de savoir comment votre langage implémente les choses au plus bas niveau. (C’est là qu’avoir une expérience en C vous aidera).

Techniquement, tous les défauts de C vous obligeraient à coder autour d’eux. vous faire écrire plus de code -> vous rendre plus expérimenté en général. Par exemple, en l’absence d’un entier portable supérieur à 32 bits, C m’a déjà fait écrire ma propre bibliothèque bignum.

Le manque de mémoire implicite, de ressources et de gestion des erreurs (garbage collection, RAII, constructeurs / destructeurs appelés automatiquement, peut-être des exceptions) oblige les utilisateurs C à écrire beaucoup de code d’initialisation, de traitement des erreurs et de nettoyage. C’est peut-être juste moi, mais je ne suis jamais fatigué d’écrire un tel code. Je vais lire la documentation de chaque fonction externe que j’appelle, je retourne à mon code et je vérifie chaque valeur de retour et tout autre élément d’indication d’échec. Cela me fait même me sentir en sécurité!

Ce dernier point est probablement le plus important en faveur de l’argument. Vous ne pouvez écrire que plusieurs paires malloc () / free () avant de commencer à parsingr la durée de vie de chaque variable que vous rencontrez dans chaque langue! Les objects à stockage automatique de C ++ ne consortingbuent pas non plus à ce désordre.

L’écriture de code C réellement portable nécessite souvent que le programmeur soit libre de nombreuses hypothèses sur le système hôte – think sizeof (), CHAR___BITS, unsigned long, UINT_MAX. Bien que cela ne m’a pas aidé à écrire un meilleur code dans d’autres langues, cela m’a aussi aidé à réfléchir à d’autres implémentations possibles: comment un minuscule microprocesseur pouvait toujours exécuter mon code C, générant un nombre incroyable d’instructions RISC pour mon simple énoncé d’une ligne. (C’est autre chose; rares sont les langues qui mappent si facilement dans ma tête. C’est peut-être juste moi.)

Bien sûr, aucun de ces arguments ne va uniquement pour C. @ S.Lott a un argument valable – Fortran pourrait être une alternative tout aussi bonne. Mais il y a tellement de code C autour! Un système informatique complet, de haut en bas – des applications aux bibliothèques, des pilotes au kernel – est disponible dans le code source en C. Ce serait un tel gaspillage que de ne pas pouvoir le lire.

En Python, disons que vous avez une fonction

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

Sur certaines versions de Python, disponibles il y a environ un an, en exécutant foo () plusieurs fois, vous obtiendrez un résultat vraiment intéressant (c’est-à-dire ["bar","bar","bar","bar] .

Il semble que quelqu’un ait implémenté les parameters par défaut en tant que variable statique (et sans le réinitialiser), ainsi des résultats inattendus se produisent.

Mon exemple était peut-être artificiel – un de mes amis qui aime réellement Python a découvert ce bug particulier, mais le fait est que tous ces langages sont implémentés en C ou C ++. Ne pas connaître et ne pas comprendre les concepts qui sont fondamentaux dans la langue de base signifie que vous n’aurez pas une compréhension approfondie des langues construites par-dessus.

Je trouve tout “pourquoi déranger avec la question C / C ++ / ASM idiot”. Si vous êtes assez enclin à apprendre une langue, cela signifie que vous êtes assez curieux pour y entrer en premier. Pourquoi s’arrêter juste avant C?

Connaître C est génial car il ne fait rien derrière le dos (GC, vérification des limites, etc.). Cela ne fait que ce que vous dites aussi. Rien n’est impliqué. Même C ++ fait des choses que vous ne dites pas aussi avec RAII (bien sûr, cela implique que l’object est détruit lorsqu’il sort de la scope, mais vous n’écrivez pas réellement). C est un excellent moyen d’apprendre ce qui se passe sous le capot de l’ordinateur, sans avoir à écrire l’assemblage.

Les codes inefficaces (par exemple, les boucles de la chaîne + =) sont généralement inefficaces dans toutes les langues. quelle différence cela fait-il si quelqu’un explique pourquoi c’est inefficace dans l’une ou l’autre langue? Connaître C, mais ne pas se rendre compte qu’une méthode est inefficace, n’est pas différent de connaître python et de ne pas réaliser la même chose.

Je pense que cela vaut la peine de connaître un langage de bas niveau, et il y a des raisons pragmatiques de choisir C:

  • C’est bas niveau, proche de l’assembleur
  • C’est répandu

Comprendre toute la stack est précieux. Parfois, vous devez déboguer les sortingpes de quelque chose. Parfois, vous ne pouvez pas résoudre un problème de performance sans connaissances de base (ce n’est souvent pas le cas, par exemple, lorsque le problème de performance est purement algorithmique, mais parfois, il l’est).

Pourquoi C est-il largement considéré comme le “fond de la stack” par excellence, et non par d’autres langues? Je pense que c’est parce que C est un langage de programmation de bas niveau, et C a gagné . Cela faisait un moment maintenant, mais C n’était pas toujours aussi dominant. Pour ne prendre qu’un exemple célèbre, les partisans de Common Lisp (qui avait ses propres façons d’écrire du code de bas niveau) espéraient que leur langue serait aussi populaire et éventuellement perdue .

Les éléments suivants sont généralement implémentés en C:

  • systèmes d’exploitation (variantes Unix, Windows, nombreux systèmes d’exploitation intégrés)
  • langages de programmation de niveau supérieur (nombreuses implémentations populaires de Java, Python, etc.)
  • (évidemment) de nombreux projets open source populaires

Je ne suis pas un spécialiste du matériel, mais je suppose que C a également beaucoup influencé la conception du processeur.

Donc, si vous croyez comprendre l’ensemble de la stack, l’apprentissage de C est, du sharepoint vue pragmatique, le meilleur choix.

En guise de mise en garde, je pense que cela vaut également la peine d’apprendre l’assembleur. Bien que C soit proche du métal, je ne comprenais pas bien C avant de devoir faire de l’assembleur. Il est parfois utile de comprendre comment les fonctions des appels sont réellement exécutées, comment les boucles for sont mises en œuvre, etc. Ce qui est moins important, mais aussi utile, est de devoir (au moins une fois) gérer un système sans mémoire virtuelle. Lorsque vous utilisez C sous Windows, Unix et certains autres systèmes d’exploitation, même l’humble malloc fait beaucoup de travail sous la couverture, qui est plus facile à apprécier, à déboguer et / ou à ajuster si vous avez déjà eu à gérer manuellement le locking et le délocking de la mémoire régions (pas que je recommande de le faire régulièrement!)