web-dev-qa-db-fra.com

Pourquoi les gens utilisent-ils C si c'est si dangereux?

J'envisage d'apprendre C.

Mais pourquoi les gens utilisent-ils le C (ou le C++) s'il peut être utilisé "dangereusement"?

Par dangereux, je veux dire avec des pointeurs et d'autres trucs similaires.

Comme la question Stack Overflow Pourquoi la fonction gets est-elle si dangereuse qu'elle ne devrait pas être utilisée? . Pourquoi les programmeurs n'utilisent-ils pas seulement Java ou Python ou un autre langage compilé comme Visual Basic?

133
Tristan
  1. C est antérieur à la plupart des autres langues auxquelles vous pensez. Une grande partie de ce que nous savons maintenant sur la façon de rendre la programmation "plus sûre" provient de l'expérience avec des langages comme C.

  2. De nombreux langages plus sûrs qui sont sortis depuis C reposent sur un temps d'exécution plus important, un ensemble de fonctionnalités plus compliqué et/ou une machine virtuelle pour atteindre leurs objectifs. En conséquence, C est resté quelque chose d'un "plus petit dénominateur commun" parmi toutes les langues populaires/grand public.

    • C est un langage beaucoup plus facile à implémenter car il est relativement petit et plus susceptible de fonctionner correctement même dans l'environnement le plus faible, de nombreux systèmes embarqués qui ont besoin de développer leurs propres compilateurs et autres outils sont plus susceptibles de fournir un compilateur fonctionnel pour C.

    • Parce que C est si petit et si simple, d'autres langages de programmation ont tendance à communiquer entre eux à l'aide d'une API de type C. C'est probablement la principale raison pour laquelle C ne mourra jamais vraiment, même si la plupart d'entre nous n'interagissent qu'avec lui via des wrappers.

  3. La plupart des langages "plus sûrs" qui tentent d'améliorer C et C++ n'essaient pas d'être des "langages systèmes" qui vous donnent un contrôle presque total sur l'utilisation de la mémoire et le comportement d'exécution de votre programme. S'il est vrai que de plus en plus d'applications de nos jours n'ont tout simplement pas besoin de ce niveau de contrôle, il y aura toujours une petite poignée de cas où cela est nécessaire (en particulier à l'intérieur des machines virtuelles et des navigateurs qui implémentent tous ces langages sûrs et agréables pour le nous autres).

    Aujourd'hui, il existe quelques langages de programmation système (Rust, Nim, D, ...) qui sont plus sûrs que C ou C++. Ils ont les avantages du recul, et se rendent compte que la plupart du temps, un tel contrôle fin n'est pas nécessaire, alors offrez une interface généralement sûre avec quelques crochets/modes dangereux auxquels vous pouvez basculer lorsque cela est vraiment nécessaire.

  4. Même au sein de C, nous avons appris de nombreuses règles et directives qui tendent à réduire considérablement le nombre de bogues insidieux qui apparaissent en pratique. Il est généralement impossible d'obtenir la norme pour appliquer ces règles rétroactivement car cela casserait trop de code existant, mais il est courant d'utiliser des avertissements du compilateur, des linters et d'autres outils d'analyse statique pour détecter ce type de problèmes facilement évitables. Le sous-ensemble de programmes C qui passent ces outils avec brio est déjà beaucoup plus sûr que "juste C", et tout programmeur C compétent de nos jours en utilisera certains.


De plus, vous ne ferez jamais un concours obscur Java aussi divertissant que le concours C obscur .

244
Ixrec

Tout d'abord, C est un langage de programmation de systèmes. Ainsi, par exemple, si vous écrivez une machine virtuelle Java ou un interpréteur Python), vous aurez besoin d'un langage de programmation système pour les écrire.

Deuxièmement, C fournit des performances que les langages comme Java et Python ne le font pas. En général, le calcul haute performance en Java et = Python utilisera des bibliothèques écrites dans un langage hautes performances tel que C pour faire le gros du travail.

Troisièmement, C a une empreinte beaucoup plus petite que des langages comme Java et Python. Cela le rend utilisable pour les systèmes embarqués, qui peuvent ne pas avoir les ressources nécessaires pour prendre en charge les grands environnements d'exécution et les demandes de mémoire de langages comme Java et Python.


Un "langage de programmation de systèmes" est un langage adapté à la construction de systèmes de puissance industrielle avec; en l'état, Java et Python ne sont pas des langages de programmation de systèmes. "Exactement ce qui fait un langage de programmation de systèmes" est en dehors du champ de cette question, mais un le langage de programmation des systèmes doit fournir un support pour travailler avec la plate-forme sous-jacente.

D'un autre côté (en réponse aux commentaires), un langage de programmation système ne pas doit être auto-hébergé. Ce problème est survenu parce que la question d'origine demandait "pourquoi les gens utilisent C", le premier commentaire demandait "pourquoi auriez-vous besoin d'un langage comme C" quand vous avez PyPy, et j'ai noté que PyPy does in fait utiliser C. Donc, il était à l'origine pertinent pour la question, mais malheureusement (et de façon confuse) "l'auto-hébergement" n'est pas réellement pertinent pour cette réponse. Je suis désolé de l'avoir soulevé.

Donc, pour résumer: Java et Python ne convient pas à la programmation de systèmes non pas parce que leurs implémentations principales sont interprétées, ou parce que les implémentations compilées en mode natif ne sont pas auto-hébergées) , mais parce qu'ils ne fournissent pas le support nécessaire pour travailler avec la plate-forme sous-jacente.

41
comingstorm

Désolé d'ajouter une autre réponse, mais je ne pense pas que les réponses existantes répondent directement à votre première phrase en déclarant:

"J'envisage d'apprendre le C"

Pourquoi? Voulez-vous faire le genre de choses que C est généralement utilisé pour aujourd'hui (par exemple, les pilotes de périphériques, les machines virtuelles, les moteurs de jeux, les bibliothèques multimédias, les systèmes embarqués, les noyaux de système d'exploitation)?

Si oui, alors oui, bien sûr, apprenez le C ou le C++ en fonction de ceux qui vous intéressent. Voulez-vous l'apprendre afin d'avoir une meilleure compréhension de ce que fait votre langage de haut niveau?

Vous continuez ensuite à mentionner les problèmes de sécurité. Vous n'avez pas nécessairement besoin d'une compréhension approfondie du C sûr pour faire ce dernier, de la même manière qu'un exemple de code dans un langage de niveau supérieur pourrait vous donner l'essentiel sans être prêt pour la production.

Écrivez du code C pour obtenir l'essentiel. Remettez-le ensuite sur l'étagère. Ne vous inquiétez pas trop de la sécurité, sauf si vous voulez écrire production code C.

30
Jared Smith

C'est une question ÉNORME avec des tonnes de réponses, mais la version courte est que chaque langage de programmation est spécialisé pour différentes situations. Par exemple, JavaScript pour le Web, C pour les trucs de bas niveau, C # pour tout Windows, etc. Il est utile de savoir ce que vous voulez faire une fois que vous connaissez la programmation pour décider du langage de programmation à choisir.

Pour répondre à votre dernier point, pourquoi C/C++ sur Java/Python, cela revient souvent à la vitesse. Je fais des jeux, et Java/C # ont récemment atteint des vitesses suffisamment bonnes pour que les jeux fonctionnent. Après tout, si vous voulez que votre jeu s'exécute à 60 images par seconde, et que vous voulez que votre jeu en fasse beaucoup (le rendu est particulièrement cher), alors vous avez besoin du code pour fonctionner aussi vite que possible. Python/Java/C #/Beaucoup d'autres fonctionnent sur des "interprètes", une couche supplémentaire de logiciels qui gère toutes les tâches fastidieuses que C/C++ ne fait pas, comme la gestion de la mémoire et la collecte des ordures. Cette surcharge supplémentaire ralentit les choses, donc presque tous les gros jeux que vous voyez ont été réalisés (au cours des 10 dernières années, en tout cas) en C ou C++. Il existe des exceptions: le moteur de jeu Unity utilise C # *, et Minecraft utilise Java, mais ce sont l'exception, pas la règle. En général, les grands jeux fonctionnant sur des langues interprétées repoussent les limites de la vitesse à laquelle cette langue peut aller.

* Même Unity n'est pas tout C #, d'énormes morceaux sont C++ et vous utilisez simplement C # pour votre code de jeu.

MODIFIER Pour répondre à certains des commentaires qui sont apparus après avoir posté ceci: Peut-être que je simplifiais trop, je donnais juste une vue d'ensemble. Avec la programmation, la réponse n'est jamais simple. Il existe des interprètes pour C, Javascript peut s'exécuter en dehors du navigateur et C # peut fonctionner sur à peu près n'importe quoi grâce à Mono. Différents langages de programmation sont spécialisés pour différents domaines, mais certains programmeurs quelque part ont probablement trouvé comment faire fonctionner n'importe quel langage dans n'importe quel contexte. Comme l'OP semblait ne pas connaître beaucoup de programmation (hypothèse de ma part, désolé si je me trompe), j'essayais de garder ma réponse simple.

Quant aux commentaires sur C # étant presque aussi rapide que C++, le mot clé est presque là. Quand j'étais à l'université, nous avons visité de nombreuses sociétés de jeux, et mon professeur (qui nous encourageait à passer du C # au C++ toute l'année) a demandé aux programmeurs de chaque entreprise de savoir pourquoi le C++ sur C #, et chacun d'eux dit que C # est trop lent. En général, il s'exécute rapidement, mais le garbage collector peut nuire aux performances car vous ne pouvez pas contrôler quand il s'exécute et il a le droit de vous ignorer s'il ne veut pas s'exécuter lorsque vous le recommandez. Si vous avez besoin de quelque chose pour être performant, vous ne voulez pas quelque chose d'aussi imprévisible que cela.

Pour répondre à mon commentaire "juste atteindre les vitesses", oui, une grande partie des augmentations de vitesse de C # proviennent d'un meilleur matériel, mais comme le framework .NET et le compilateur C # se sont améliorés, il y a eu quelques accélérations.

A propos du commentaire "les jeux sont écrits dans la même langue que le moteur", cela dépend. Certains le sont, mais beaucoup sont écrits dans un hybride de langues. Unreal peut faire UnrealScript et C++, Unity fait C # Javascript et Boo, de nombreux autres moteurs écrits en C ou C++ utilisent Python ou Lua comme langages de script. Il n'y a pas de réponse simple là-bas.

Et juste parce que ça m'a dérangé de lire "qui se soucie si votre jeu tourne à 200fps ou 120fps", si votre jeu tourne plus vite que 60fps, vous perdez probablement du temps processeur, car le moniteur moyen ne rafraîchit même pas cela vite. Certains haut de gamme et les plus récents le font, mais ce n'est pas standard (encore ...).

Et à propos de la remarque "ignorer des décennies de technologie", je suis encore au début de la vingtaine, donc quand j'extrapole en arrière, je fais surtout écho à ce que les programmeurs plus âgés et plus expérimentés m'ont dit. Évidemment, cela sera contesté sur un site comme celui-ci, mais cela vaut la peine d'être considéré.

14
Cody

C'est drôle que vous affirmiez que C n'est pas plus sûr car "il a des pointeurs". L'inverse est vrai: Java et C # n'ont pratiquement que des pointeurs (pour les types non natifs). L'erreur la plus courante dans Java est probablement l'exception de pointeur nul) (cf. https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare ). La deuxième erreur la plus courante est probablement la détention de références cachées à les objets inutilisés (par exemple, les dialogues fermés ne sont pas éliminés) qui ne peuvent donc pas être libérés, conduisant à des programmes de longue durée avec une empreinte mémoire toujours croissante.

Il existe deux mécanismes de base qui rendent C # et Java plus sûr et plus sûr de deux manières différentes:

  • La récupération de place rend moins probable que le programme tente d'accéder aux objets jetés. Cela rend le programme moins susceptible de se terminer de façon inattendue. Par opposition à C, Java et C # par défaut allouent dynamiquement les données non natives. Cela rend la logique du programme plus complexe, mais le garbage collection intégré - à un coût - prend sur la partie difficile.

Les pointeurs intelligents récents de C++ facilitent ce travail pour les programmeurs.

  • Java et C # se compilent en un code intermédiaire qui est interprété/exécuté par un temps d'exécution élaboré. Cela ajoute un niveau de sécurité car le temps d'exécution peut détecter les activités illicites d'un programme. Même si le programme est codé de manière non sécurisée (ce qui est possible dans les deux langues), le temps d'exécution respectif empêche en théorie une "percée" dans le système.
    Le temps d'exécution ne protège pas contre par exemple tentative de dépassement de tampon, mais en théorie ne permet pas d'exploiter de tels programmes. Avec C et C++, en revanche, le programmeur doit coder en toute sécurité afin d'éviter les exploits. Ceci n'est généralement pas réalisé immédiatement mais nécessite des révisions et des itérations.

Il convient de noter cependant que le temps d'exécution élaboré est également un risque pour la sécurité. Il me semble qu'Oracle met à jour la JVM toutes les deux semaines en raison de problèmes de sécurité récemment découverts. Il est bien sûr beaucoup plus difficile de vérifier la JVM qu'un seul programme.

La sécurité d'un temps d'exécution élaboré est donc ambiguë et trompeuse dans une certaine mesure: votre programme C moyen peut, avec des révisions et des itérations, être raisonnablement sécurisé. Votre programme Java Java est aussi sûr que la JVM, c'est-à-dire pas vraiment. Jamais.

L'article sur gets() auquel vous vous connectez reflète les décisions historiques de la bibliothèque qui seraient prises différemment aujourd'hui, pas le langage principal.

Parce que la "sécurité" coûte de la vitesse, les langues "plus sûres" fonctionnent à une vitesse plus lente.

Vous demandez pourquoi utiliser un langage "dangereux" comme C ou C++, demandez à quelqu'un de vous écrire un pilote vidéo ou similaire en Python ou Java, etc. et voyez ce que vous pensez de la "sécurité": )

Plus sérieusement cependant, vous devez être aussi proche de la mémoire centrale de la machine pour pouvoir manipuler les pixels, les registres, etc ... Java ou Python ne peut pas faire cela avec n'importe quel type de vitesse digne de performances ... C et C++ vous permettent tous les deux de le faire via des pointeurs et autres ...

10
Wintermut3

Outre tout ce qui précède, il existe également un cas d'utilisation assez courant, qui utilise C comme bibliothèque commune pour d'autres langages.

Fondamentalement, presque toutes les langues ont une interface API vers C.

Exemple simple, essayez de créer une application commune pour Linux/IOS/Android/Windows. Outre tous les outils disponibles, nous avons fini par créer une bibliothèque principale en C, puis changer l'interface graphique pour chaque environnement, c'est-à-dire:

  • IOS: ObjectiveC peut utiliser nativement les bibliothèques C
  • Android: Java + JNI
  • Linux/Windows/MacOS: Avec GTK/.Net, vous pouvez utiliser des bibliothèques natives. Si vous utilisez Python, Perl, Ruby chacun d'eux a des interfaces API natives (Java à nouveau avec JNI).

Mes deux centimes,

9
Nito

Une difficulté fondamentale avec C est que le nom est utilisé pour décrire un certain nombre de dialectes avec une syntaxe identique mais une sémantique très différente. Certains dialectes sont beaucoup plus sûrs que d'autres.

Dans C tel que conçu à l'origine par Dennis Ritchie, les instructions C seraient généralement mappées aux instructions de la machine de manière prévisible. Parce que C pouvait fonctionner sur des processeurs qui se comportaient différemment lorsque des choses comme un dépassement arithmétique signé se produisaient, un programmeur qui ne savait pas comment une machine se comporterait en cas de dépassement arithmétique ne saurait pas non plus quel code C exécuté sur cette machine se comporterait, mais si une machine était connue pour se comporter d'une certaine manière (par exemple, un enveloppement silencieux à deux compléments), les implémentations sur cette machine feraient généralement de même. L'une des raisons pour lesquelles C a la réputation d'être rapide est que, dans les cas où les programmeurs savaient que le comportement naturel d'une plate-forme dans les scénarios de cas Edge répondait à leurs besoins, il n'était pas nécessaire que le programmeur ou le compilateur écrive du code pour générer de tels scénarios . Il était vital que tout code utilisant des pointeurs pour accéder à la mémoire s'assure que les pointeurs n'étaient jamais utilisés pour accéder à des choses qu'ils ne devraient pas, ce qui nécessiterait généralement de s'assurer que les calculs impliquant des pointeurs ne débordent pas, mais ne nécessiteraient pas de paranoïa sur des choses comme l'arithmétique débordement dans d'autres contextes.

Malheureusement, les rédacteurs du compilateur ont estimé que, puisque la norme n'impose aucune exigence sur ce que les implémentations doivent faire dans de tels cas (laxisme qui était destiné à permettre des implémentations matérielles qui pourraient ne pas se comporter de manière prévisible), les compilateurs devraient se sentir libres de générer du code qui annule les lois. de temps et de causalité.

Considérez quelque chose comme:

int hey(int x)
{
   printf("%d", x);
   return x*10000;
}
void wow(int x)
{
  if (x < 1000000)
    printf("QUACK!");
  hey(x);    
}

La théorie du compilateur hyper-moderne (mais à la mode) suggérerait que le compilateur devrait produire "QUACK!" inconditionnellement, puisque dans tous les cas où la condition était fausse, le programme finirait par invoquer un comportement non défini effectuant une multiplication dont le résultat allait être ignoré de toute façon. Étant donné que la norme permettrait à un compilateur de faire tout ce qu'il veut dans un tel cas, il permet au compilateur de produire "QUACK!".

Alors que C était plus sûr que le langage d'assemblage, lors de l'utilisation de compilateurs hyper-modernes, l'inverse est vrai. Dans le langage d'assemblage, un débordement d'entier peut entraîner un calcul sans résultat, mais sur la plupart des plates-formes, ce sera l'étendue de ses effets. Si les résultats finissent par être ignorés de toute façon, le débordement n'aura pas d'importance. Dans le C hyper-moderne, cependant, même ce qui serait normalement des formes "bénignes" de comportement indéfini (comme un débordement d'entier dans un calcul qui finit par être ignoré) peut provoquer l'exécution arbitraire de programme.

7
supercat

Qu'est-ce qui est "dangereux"?

L'affirmation que C est "dangereux" est un sujet de discussion fréquent dans les guerres de flammes du langage (le plus souvent par rapport à Java). Cependant, les preuves de cette affirmation ne sont pas claires.

C est un langage avec un ensemble particulier de fonctionnalités. Certaines de ces fonctionnalités peuvent autoriser certains types d'erreurs qui ne sont pas autorisés par d'autres types de langages (les risques de gestion de la mémoire de C sont généralement mis en évidence). Cependant, ce n'est pas la même chose qu'un argument selon lequel C est plus dangereux que les autres langages dans l'ensemble. Je ne connais personne qui ait fourni des preuves convaincantes sur ce point.

De plus, "dangereux" dépend du contexte: qu'essayez-vous de faire et quels types de risques vous inquiètent?

Dans de nombreux contextes, je considérerais le C plus "dangereux" qu'un langage de haut niveau, car il vous oblige à faire plus d'implémentation manuelle des fonctionnalités de base, augmentant le risque de bugs. Par exemple, effectuer un traitement de texte de base ou développer un site Web en C serait généralement stupide, car d'autres langues ont des fonctionnalités qui rendent cela beaucoup plus facile.

Cependant, C et C++ sont largement utilisés pour les systèmes critiques, car un langage plus petit avec un contrôle plus direct de hardward est considéré comme "plus sûr" dans ce contexte. De ne très bonne réponse Stack Overflow :

Bien que le C et le C++ n'aient pas été spécifiquement conçus pour ce type d'application, ils sont largement utilisés pour les logiciels intégrés et critiques pour la sécurité pour plusieurs raisons. Les principales propriétés de note sont le contrôle de la gestion de la mémoire (ce qui vous permet d'éviter d'avoir à récupérer des ordures, par exemple), des bibliothèques d'exécution de base simples et bien déboguées et la prise en charge d'outils matures. Un grand nombre des chaînes d'outils de développement intégrées utilisées aujourd'hui ont été développées pour la première fois dans les années 1980 et 1990, alors qu'il s'agissait de la technologie actuelle et proviennent de la culture Unix qui prévalait à l'époque, de sorte que ces outils restent populaires pour ce type de travail.

Bien que le code de gestion manuelle de la mémoire doit être soigneusement vérifié pour éviter les erreurs, il permet un certain contrôle sur les temps de réponse des applications qui n'est pas disponible avec les langues qui dépendent de la collecte des ordures. Les bibliothèques de base d'exécution des langages C et C++ sont relativement simples, matures et bien comprises, elles font donc partie des plates-formes les plus stables disponibles.

5
user82096

Pour ajouter aux réponses existantes, c'est bien beau de dire que vous allez choisir Python ou PHP pour votre projet, en raison de leur sécurité relative) Mais quelqu'un doit implémenter ces langages et, quand ils le feront, ils le feront probablement en C. (Ou bien, quelque chose comme ça.)

C'est pourquoi les gens utilisent C - pour créer les outils moins dangereux que vous souhaitez utiliser.

Raisons historiques. Je n'ai pas souvent la possibilité d'écrire du code flambant neuf, la plupart du temps, je peux maintenir et étendre les vieux trucs qui fonctionnent depuis des décennies. Je suis juste content que ce soit C et pas Fortran.

Je peux m'énerver quand un élève dit: "mais pourquoi diable fais-tu ce terrible X alors que tu pourrais faire le Y?". Eh bien, X est le travail que j'ai et il paie très bien les factures. J'ai fait Y à l'occasion et c'était amusant, mais X est ce que la plupart d'entre nous font.

5
RedSonja

Permettez-moi de reformuler votre question:

J'envisage d'apprendre [outil].

Mais pourquoi les gens utilisent-ils [outil] (ou [outil connexe]) si [ils] peuvent être utilisés "dangereusement"?

Tout outil intéressant peut être utilisé dangereusement, y compris les langages de programmation. Vous apprenez plus pour pouvoir faire plus (et pour que moins de danger soit créé lorsque vous utilisez l'outil). En particulier, vous apprenez l'outil afin de pouvoir faire ce pour quoi cet outil est bon (et peut-être reconnaître quand cet outil est le meilleur outil des outils que vous connaissez).

Par exemple, si vous devez placer un trou cylindrique de 6 mm de diamètre et 5 cm de profondeur dans un bloc de bois, une perceuse est un bien meilleur outil qu'un analyseur LALR. Si vous savez ce que sont ces deux outils, vous savez quel est le bon outil. Si vous savez déjà utiliser une perceuse, le tour est joué !, trou.

C n'est qu'un autre outil. C'est mieux pour certaines tâches que pour d'autres. Les autres réponses ici répondent à cela. Si vous apprenez du C, vous finirez par reconnaître quand c'est le bon outil et quand il ne l'est pas.

2
Eric Towers

J'envisage d'apprendre C

Il n'y a aucune raison spécifique de ne pas apprendre le C, mais je suggère le C++. Il offre une grande partie de ce que fait C (puisque C++ est un super ensemble de C), avec une grande quantité d '"extras". Apprendre le C avant C++ n'est pas nécessaire - ce sont en fait des langages distincts.

Autrement dit, si C était un ensemble d'outils pour le travail du bois, ce serait probablement:

  • marteau
  • ongles
  • scie à main
  • perceuse à main
  • ponceuse à bloc
  • ciseau (peut-être)

Vous pouvez construire n'importe quoi avec ces outils - mais tout Nice nécessite potentiellement beaucoup de temps et de compétences.

C++ est la collection d'outils électriques de votre quincaillerie locale.

Si vous vous en tenez aux fonctionnalités de base du langage pour commencer, C++ a relativement peu de courbe d'apprentissage supplémentaire.

Mais pourquoi les gens utilisent-ils le C (ou le C++) s'il peut être utilisé "dangereusement"?

Parce que certaines personnes ne veulent pas de meubles IKEA. =)

Sérieusement, bien que de nombreux langages "supérieurs" au C ou au C++ puissent avoir des choses qui les rendent (potentiellement) "plus faciles" à utiliser dans certains aspects, ce n'est pas toujours une bonne chose. Si vous n'aimez pas la façon dont quelque chose est fait ou si une fonctionnalité n'est pas fournie, vous ne pouvez probablement pas faire grand-chose. D'un autre côté, C et C++ fournissent suffisamment de fonctionnalités de langage "bas niveau" (y compris des pointeurs) pour que vous puissiez accéder à beaucoup de choses assez directement (en particulier matériel ou système d'exploitation) ou le construire vous-même, ce qui peut ne pas être possible dans d'autres langues telles que mises en œuvre.

Plus précisément, C possède l'ensemble des fonctionnalités suivantes qui le rendent souhaitable pour de nombreux programmeurs:

  • Vitesse - En raison de sa relative simplicité et des optimisations du compilateur au fil des ans, il est nativement très rapide. De plus, beaucoup de gens ont trouvé beaucoup de raccourcis vers des objectifs spécifiques lors de l'utilisation du langage, ce qui le rend potentiellement encore plus rapide.
  • Taille - Pour des raisons similaires à celles répertoriées pour la vitesse, les programmes C peuvent être très petits (en termes de taille exécutable et d’utilisation de la mémoire), ce qui est souhaitable pour les environnements à mémoire limitée (c'est-à-dire embarqués ou mobiles).
  • Compatibilité - C existe depuis longtemps et tout le monde a des outils et des bibliothèques pour cela. Le langage lui-même n'est pas difficile non plus - il attend d'un processeur qu'il exécute des instructions et que la mémoire contienne des trucs et c'est tout.

    De plus, il existe quelque chose connu sous le nom de Application Binary Interface (ABI) . En bref, c'est un moyen pour les programmes de communiquer au niveau du code machine, ce qui peut présenter des avantages par rapport à Application Programming Interface (API) . Alors que d'autres langages tels que C++ peuvent avoir un ABI, ceux-ci sont généralement moins uniformes (convenus) que les C, donc C constitue un bon langage de base lorsque vous souhaitez utiliser un ABI pour communiquer avec un autre programme pour une raison quelconque.

Pourquoi les programmeurs n'utilisent-ils pas seulement Java ou Python ou un autre langage compilé comme Visual Basic?

Efficacité (et parfois des schémas de gestion de la mémoire qui ne peuvent pas être mis en œuvre sans un accès relativement direct à la mémoire).

L'accès direct à la mémoire avec des pointeurs introduit beaucoup de trucs soignés (généralement rapides) lorsque vous pouvez mettre vos pattes crasseuses sur les petits et les zéros dans vos compartiments de mémoire directement et ne pas avoir à attendre ce vieux professeur pour distribuer les jouets juste au moment du jeu, puis récupérez-les à nouveau.

En bref, l'ajout de trucs crée potentiellement du retard ou introduit une complexité indésirable.

En ce qui concerne les langages scriptés et cet acabit, vous devez travailler dur pour que les langages nécessitant des programmes secondaires s'exécutent aussi efficacement que C (ou tout autre langage compilé). L'ajout d'un interprète à la volée introduit de manière inhérente la possibilité de réduire la vitesse d'exécution et d'augmenter l'utilisation de la mémoire car vous ajoutez un autre programme au mixage. L'efficacité de vos programmes repose autant sur l'efficacité de ce programme secondaire que sur la qualité (médiocre =)) de l'écriture de votre code de programme d'origine. Sans oublier que votre programme dépend souvent complètement du deuxième programme pour même s'exécuter. Ce deuxième programme n'existe pas pour une raison quelconque sur un système particulier? Pas de code.

En fait, introduire n'importe quoi "extra" ralentit ou complique potentiellement votre code. Dans les langages "sans pointeurs effrayants", vous attendez toujours que d'autres morceaux de code soient nettoyés derrière vous ou sinon vous découvrez des façons "sûres" de faire les choses - parce que votre programme est toujours faisant le mêmes opérations d'accès à la mémoire que pour les pointeurs. Vous n'êtes tout simplement pas celui qui le gère (donc vous ne pouvez pas le f * ck up, génie = P).

Par dangereux, je veux dire avec des pointeurs et d'autres trucs similaires. [...] Comme la question Stack Overflow Pourquoi la fonction gets est-elle si dangereuse qu'elle ne devrait pas être utilisée?

Par la réponse acceptée:

"Il est resté une partie officielle du langage jusqu'à la norme ISO C de 1999, mais il a été officiellement supprimé par la norme de 2011. La plupart des implémentations C le supportent toujours, mais au moins gcc émet un avertissement pour tout code qui l'utilise."

L'idée que parce que quelque chose peut être fait dans une langue, cela doit être fait est idiot. Les langues ont des défauts qui se corrigent. Pour des raisons de compatibilité avec du code plus ancien, cette construction peut toujours être utilisée. Mais rien n'oblige (probablement) un programmeur à utiliser gets () et, en fait, cette commande a été essentiellement remplacée par des alternatives plus sûres.

Plus précisément, le problème avec gets () n'est pas un problème de pointeur en soi. C'est un problème avec une commande qui ne sait pas nécessairement comment utiliser la mémoire en toute sécurité. Dans un sens abstrait, ce sont toutes des questions de pointeur - lire et écrire des choses que vous n'êtes pas censé faire. Ce n'est pas un problème avec les pointeurs; c'est un problème avec l'implémentation du pointeur.

Pour clarifier, les pointeurs ne sont pas dangereux jusqu'à ce que vous accédiez accidentellement à un emplacement de mémoire auquel vous n'aviez pas l'intention. Et même dans ce cas, cela ne garantit pas que votre ordinateur fondra ou explosera. Dans la plupart des cas, votre programme cessera de fonctionner (correctement).

Cela dit, parce que les pointeurs fournissent un accès aux emplacements de mémoire et parce que les données et le code exécutable existent ensemble en mémoire, il y a suffisamment de risque réel de corruption accidentelle pour que vous souhaitiez gérer correctement la mémoire.

À ce stade, parce que les opérations d'accès à la mémoire vraiment directes offrent généralement moins d'avantages en général qu'elles ne l'étaient il y a des années, même les non - langages récupérés comme C++ ont introduit des choses telles que pointeurs intelligents pour aider à combler l'écart entre l'efficacité de la mémoire et la sécurité.

En résumé, il y a très peu de raisons de craindre le pointeur tant qu'il est utilisé en toute sécurité. Prenez juste un indice de la version de South Park de Steve "The Crocodile Hunter" Irwin - ne vous promenez pas en mettant le pouce dans les trous de cul des crocs .

1
Anaksunaman

Comme toujours, le langage de programmation n'est qu'une conséquence de la résolution de problèmes. En fait, vous devez apprendre non seulement le C, mais de nombreux langages différents (et d'autres façons de programmer un ordinateur, qu'il s'agisse d'outils GUI ou d'interprètes de commandes) pour avoir une boîte à outils décente à utiliser lors de la résolution de problèmes.

Parfois, vous constaterez qu'un problème se prête bien à quelque chose qui est inclus dans les bibliothèques par défaut Java, dans un tel cas, vous pouvez choisir Java pour en tirer parti). Dans d'autres cas, il se peut que vous deviez faire quelque chose sur Windows qui est beaucoup plus simple dans le runtime .NET, vous pouvez donc utiliser C # ou VB. Il pourrait y avoir un outil graphique ou un script de commande qui résout votre problème, puis vous pouvez les utiliser. Vous devrez peut-être écrire une application GUI sur plusieurs plates-formes, Java pourrait être une option, étant donné les bibliothèques incluses dans le JDK, mais là encore, une plate-forme cible peut ne pas avoir de JRE alors peut-être que vous choisissez plutôt C et SDL (ou similaire).

C a une position importante dans cet ensemble d'outils, car il est général, petit et rapide et compile également pour le code d'usinage. Il est également pris en charge sur chaque plate-forme sous le soleil (non sans recompilation cependant).

En bout de ligne, vous devez apprendre autant d'outils, de langues et de paradigmes que possible.

Veuillez vous éloigner de l'état d'esprit: "Je suis un programmeur X" (X = C, C++, Java, etc.)

Utilisez simplement "Je suis programmeur".

Un programmeur résout les problèmes et conçoit des algorithmes en demandant aux machines d'effectuer la charge de travail. Fin de l'histoire. Cela n'a rien à voir avec la langue. Votre compétence la plus importante est la résolution de problèmes et la répartition logique des problèmes structurés, la compétence/le choix de la langue est TOUJOURS secondaire et/ou une conséquence de la nature du problème.

Un chemin intéressant si vous êtes intéressé par C est d'étendre vos compétences avec Go. Go est vraiment un C amélioré, avec un garbage collection et des interfaces, ainsi qu'un modèle/canaux de threading Nice intégré, qui apportent également de nombreux avantages du C (comme l'arithmétique des pointeurs et la compilation en code machine).

1
Richard Tyregrim

Cela dépend de ce que vous comptez en faire. C a été conçu en remplacement du langage d'assemblage et est le langage de haut niveau le plus proche du langage machine. Il présente donc de faibles frais généraux en termes de taille et de performances et convient à la programmation de systèmes et à d'autres tâches qui nécessitent un faible encombrement et se rapprochent du matériel sous-jacent.

0
Jonathan Rosenne

Lorsque vous travaillez au niveau des bits et octets, de la mémoire en tant que collecte de données homogène brute, comme cela serait souvent nécessaire pour implémenter efficacement les allocateurs et les structures de données les plus efficaces, il n'y a aucune sécurité à avoir. La sécurité est principalement un concept fort lié au type de données, et un allocateur de mémoire ne fonctionne pas avec les types de données. Il fonctionne avec des bits et des octets pour regrouper ces mêmes bits et octets représentant potentiellement un type de données à un moment et un autre plus tard.

Peu importe si vous utilisez C++ dans ce cas. Vous seriez encore en train de saupoudrer static_casts partout dans le code à partir de void* pointeurs et toujours travailler avec des bits et des octets et traiter simplement plus de tracas liés au respect du système de type dans ce contexte que C qui a un système de type beaucoup plus simple où vous êtes libre de memcpy bits et octets autour sans se soucier de bulldozer sur le système de type.

En fait, il est souvent plus difficile de travailler en C++, un langage globalement plus sûr, dans de tels contextes de bas niveau de bits et d'octets sans écrire de code encore plus dangereux que vous ne le feriez en C, car vous pourriez être en train de bulldozer sur le système de type de C++ et faire des choses comme écraser les vptrs et ne pas appeler les constructeurs et destructeurs de copie aux moments appropriés. Si vous prenez le temps approprié pour respecter ces types et utiliser le placement de nouveaux et invoquer manuellement les dtors et ainsi de suite, vous serez alors exposé au monde de la gestion des exceptions dans un contexte trop bas pour que RAII soit pratique et atteignant l'exception - la sécurité dans un contexte aussi bas est très difficile (vous devez faire comme si n'importe quelle fonction peut lancer et saisir toutes les possibilités et annuler tous les effets secondaires comme une transaction indivisible comme si de rien n'était). Le code C peut souvent supposer "en toute sécurité" que vous pouvez traiter tout type de données instancié en C comme de simples bits et octets sans violer le système de type et invoquer un comportement indéfini ou rencontrer des exceptions.

Et il serait impossible d'implémenter de tels allocateurs dans des langues qui ne vous permettent pas de devenir "dangereux" ici; vous devez vous appuyer sur les allocateurs qu'ils fournissent (implémentés le plus probablement en C ou C++) et espérer que cela soit assez bon pour vos besoins. Et il existe presque toujours des allocateurs et des structures de données plus efficaces mais moins généraux adaptés à vos besoins spécifiques, mais beaucoup plus étroitement applicables, car ils sont spécifiquement adaptés à vos besoins.

La plupart des gens n'ont pas besoin des goûts de C ou C++ car ils peuvent simplement appeler du code implémenté à l'origine en C ou C++ ou peut-être même Assembly déjà implémenté pour eux. Beaucoup pourraient bénéficier d'innover au niveau supérieur, comme enchaîner un programme d'image qui utilise simplement des bibliothèques de fonctions de traitement d'image existantes déjà implémentées en C où ils n'innovent pas tellement au niveau le plus bas de bouclage à travers des pixels individuels, mais peut-être offrant une interface utilisateur et un flux de travail très conviviaux jamais vus auparavant. Dans ce cas, si le but du logiciel est simplement de faire des appels de haut niveau dans des bibliothèques de bas niveau ("traiter toute cette image pour moi, pas pour chaque pixel, faire quelque chose"), alors il pourrait sans doute être une optimisation prématurée d'essayer même de commencer à écrire une telle application en C.

Mais si vous faites quelque chose de nouveau à bas niveau où cela aide à accéder aux données de bas niveau comme un tout nouveau filtre d'image jamais vu auparavant, c'est assez rapide pour travailler sur la vidéo HD en temps réel, alors vous devez généralement obtenir un peu dangereux.

Il est facile de tenir ces choses pour acquises. Je me souviens d'une publication sur Facebook avec quelqu'un soulignant comment il était possible de créer un jeu vidéo 3D avec Python avec l'implication que les langages de bas niveau deviennent obsolètes, et c'était certainement un jeu d'aspect décent . Mais Python effectuait des appels de haut niveau dans les bibliothèques implémentées en C pour faire tout le travail lourd. Vous ne pouvez pas créer Unreal Engine 4 en faisant simplement des appels de haut niveau dans les bibliothèques existantes. . Unreal Engine 4 is la bibliothèque. Il a fait toutes sortes de choses qui n'ont jamais existé dans d'autres bibliothèques et moteurs, de l'éclairage à même son système de plan nodal et comment il peut compiler et exécuter du code à la volée. Si vous voulez innover au niveau du bas moteur/noyau/noyau, alors vous devez obtenir de bas niveau. Si tous les développeurs de jeux passaient à des langues sûres de haut niveau, il n'y aurait pas d'Unreal Engine 5, ou 6, ou 7 Ce serait probablement des gens qui utilisent Unreal Engine 4 décennies plus tard parce que vous ne pouvez pas innover au niveau requis pour sortir avec un moteur de nouvelle génération e en faisant simplement des appels de haut niveau dans l'ancien.

0
user204677