Considérons les exemples Hello World suivants en C et C ++:
#include <stdio.h>
int main()
{
printf("Hello world\n");
return 0;
}
#include <iostream>
int main()
{
std::cout<<"Hello world"<<std::endl;
return 0;
}
Quand je les compile dans godbolt à l'assemblage, la taille du code C n'est que de 9 lignes ( gcc -O3
):
.LC0:
.string "Hello world"
main:
sub rsp, 8
mov edi, OFFSET FLAT:.LC0
call puts
xor eax, eax
add rsp, 8
ret
Mais la taille du code C ++ est de 22 lignes ( g++ -O3
):
.LC0:
.string "Hello world"
main:
sub rsp, 8
mov edx, 11
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
xor eax, eax
add rsp, 8
ret
_GLOBAL__sub_I_main:
sub rsp, 8
mov edi, OFFSET FLAT:_ZStL8__ioinit
call std::ios_base::Init::Init() [complete object constructor]
mov edx, OFFSET FLAT:__dso_handle
mov esi, OFFSET FLAT:_ZStL8__ioinit
mov edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
add rsp, 8
jmp __cxa_atexit
... ce qui est beaucoup plus grand.
Il est connu qu'en C ++, vous payez ce que vous mangez. Alors, dans ce cas, qu'est-ce que je paie?
eat
associé à C ++. Je crois que vous voulez dire: "Vous ne payez que ce que vous utilisez "?eat
est plus ambigu et doit être évité.Réponses:
Ce que vous payez, c'est d'appeler une bibliothèque lourde (pas aussi lourde que l'impression dans la console). Vous initialisez un
ostream
objet. Il y a du stockage caché. Ensuite, vous appelezstd::endl
ce qui n'est pas synonyme de\n
. Laiostream
bibliothèque vous aide à ajuster de nombreux paramètres et à mettre le fardeau sur le processeur plutôt que sur le programmeur. C'est ce que vous payez.Passons en revue le code:
Initialisation d'un objet ostream + cout
Appel à
cout
nouveau pour imprimer une nouvelle ligne et rincerInitialisation du stockage statique:
Aussi, il est essentiel de faire la distinction entre la langue et la bibliothèque.
BTW, ce n'est qu'une partie de l'histoire. Vous ne savez pas ce qui est écrit dans les fonctions que vous appelez.
la source
cout; printf; cout
écritures dans l'ordre (puisqu'ils ont leurs propres tampons). Le second va désynchronisercout
etcin
, ce qui amèneracout; cin
potentiellement à demander à l'utilisateur des informations en premier. Le rinçage le forcera à se synchroniser uniquement lorsque vous en aurez réellement besoin.std::cout
est plus puissant et compliqué queprintf
. Il prend en charge des éléments tels que les paramètres régionaux, les indicateurs de mise en forme avec état, etc.Si vous n'en avez pas besoin, utilisez
std::printf
oustd::puts
- ils sont disponibles dans<cstdio>
.Je tiens également à préciser que C ++ ! = La bibliothèque standard C ++. La bibliothèque standard est censée être polyvalente et "assez rapide", mais elle sera souvent plus lente qu'une implémentation spécialisée de ce dont vous avez besoin.
D'autre part, le langage C ++ s'efforce de rendre possible l'écriture de code sans payer de coûts cachés supplémentaires inutiles (par exemple, opt-in
virtual
, pas de garbage collection).la source
Vous ne comparez pas C et C ++. Vous comparez
printf
etstd::cout
, qui sont capables de différentes choses (locales, formatage avec état, etc.).Essayez d'utiliser le code suivant à des fins de comparaison. Godbolt génère le même assemblage pour les deux fichiers (testé avec gcc 8.2, -O3).
principal c:
main.cpp:
la source
Vos annonces comparent en effet des pommes et des oranges, mais pas pour la raison impliquée dans la plupart des autres réponses.
Vérifions ce que fait réellement votre code:
C:
"Hello world\n"
C ++:
"Hello world"
dansstd::cout
std::endl
manipulateur dansstd::cout
Apparemment, votre code C ++ fait deux fois plus de travail. Pour une comparaison équitable, nous devons combiner ceci:
… Et tout à coup votre code d'assemblage pour
main
ressemble beaucoup à C:En fait, on peut comparer les codes C et C ++ ligne par ligne, et il y a très peu de différences :
La seule vraie différence est qu'en C ++, nous appelons
operator <<
avec deux arguments (std::cout
et la chaîne). Nous pourrions supprimer même cette légère différence en utilisant un équivalent C plus proche:,fprintf
qui a également un premier argument spécifiant le flux.Cela laisse le code d'assembly pour
_GLOBAL__sub_I_main
, qui est généré pour C ++ mais pas C. C'est la seule vraie surcharge visible dans cette liste d'assembly (il y a plus, une surcharge invisible pour les deux langues, bien sûr). Ce code exécute une configuration unique de certaines fonctions de bibliothèque standard C ++ au démarrage du programme C ++.Mais, comme expliqué dans d'autres réponses, la différence pertinente entre ces deux programmes ne se trouvera pas dans la sortie d'assemblage de la
main
fonction, car tout le gros du travail se passe dans les coulisses.la source
_start
mais son code fait partie de la bibliothèque d'exécution C. En tout cas, cela se produit à la fois pour C et C ++.std::cout
et passe les E / S à l'implémentation stdio (qui utilise ses propres mécanismes de mise en mémoire tampon). En particulier, lorsque vous êtes connecté à (ce que l'on sait être) un terminal interactif, par défaut, vous ne verrez jamais une sortie entièrement mise en mémoire tampon lors de l'écriture dansstd::cout
. Vous devez désactiver explicitement la synchronisation avec stdio si vous souhaitez que la bibliothèque iostream utilise ses propres mécanismes de mise en mémoire tampon pourstd::cout
.printf
n'est pas nécessaire de vider les flux ici. En fait, dans un cas d'utilisation courant (sortie redirigée vers un fichier), vous constaterez généralement que l'printf
instruction ne se vide pas . Ce n'est que lorsque la sortie est en tampon de ligne ou sans tampon que leprintf
déclenchement déclenchera un vidage.C'est simple. Vous payez
std::cout
. «Vous ne payez que ce que vous mangez» ne veut pas dire «vous obtenez toujours les meilleurs prix». Bien sûr,printf
c'est moins cher. On peut soutenir questd::cout
c'est plus sûr et plus polyvalent, donc son coût plus élevé est justifié (cela coûte plus cher, mais offre plus de valeur), mais cela manque le point. Vous n'utilisez pasprintf
, vous utilisezstd::cout
, donc vous payez pour l'utilisationstd::cout
. Vous ne payez pas pour l'utilisationprintf
.Les fonctions virtuelles en sont un bon exemple. Les fonctions virtuelles ont un coût d'exécution et des exigences d'espace - mais uniquement si vous les utilisez réellement . Si vous n'utilisez pas de fonctions virtuelles, vous ne payez rien.
Quelques remarques
Même si le code C ++ évalue plus d'instructions d'assemblage, il s'agit toujours d'une poignée d'instructions, et toute surcharge de performances est toujours probablement éclipsée par les opérations d'E / S réelles.
En fait, parfois c'est encore mieux que "en C ++, vous payez ce que vous mangez". Par exemple, le compilateur peut déduire que l'appel de fonction virtuelle n'est pas nécessaire dans certaines circonstances et le transformer en appel non virtuel. Cela signifie que vous pouvez obtenir des fonctions virtuelles gratuitement . N'est-ce pas génial?
la source
La "liste d'assemblage pour printf" n'est PAS pour printf, mais pour les put (sorte d'optimisation du compilateur?); printf est bien plus complexe que met ... n'oubliez pas!
la source
std::cout
les internes de, qui ne sont pas visibles dans la liste de l'assemblage.puts
, qui semble identique à un appel àprintf
si vous ne transmettez qu'une seule chaîne de format et zéro argument supplémentaire. (sauf qu'il y aura aussi unxor %eax,%eax
parce que nous passons zéro argument FP dans les registres à une fonction variadique.) Ni l'un ni l'autre ne sont l'implémentation, juste en passant un pointeur vers une chaîne vers la fonction de bibliothèque. Mais oui, l'optimisationprintf
versputs
est quelque chose que gcc fait pour les formats qui n'ont que"%s"
, ou quand il n'y a pas de conversion, et la chaîne se termine par une nouvelle ligne.Je vois des réponses valables ici, mais je vais entrer un peu plus dans les détails.
Allez au résumé ci-dessous pour la réponse à votre question principale si vous ne voulez pas parcourir tout ce mur de texte.
Abstraction
Vous payez pour l' abstraction . Etre capable d'écrire du code plus simple et plus convivial a un coût. En C ++, qui est un langage orienté objet, presque tout est un objet. Lorsque vous utilisez un objet, trois choses principales se produiront toujours sous le capot:
init()
méthode). Habituellement, l'allocation de mémoire se produit sous le capot comme la première chose de cette étape.Vous ne le voyez pas dans le code, mais chaque fois que vous utilisez un objet, les trois choses ci-dessus doivent se produire d'une manière ou d'une autre. Si vous deviez tout faire manuellement, le code serait évidemment beaucoup plus long.
Désormais, l'abstraction peut être faite efficacement sans ajouter de surcharge: l'inclusion de méthodes et d'autres techniques peuvent être utilisées à la fois par les compilateurs et les programmeurs pour supprimer les frais généraux d'abstraction, mais ce n'est pas votre cas.
Que se passe-t-il vraiment en C ++?
Le voici, décomposé:
std::ios_base
classe est initialisée, qui est la classe de base pour tout ce qui concerne les E / S.std::cout
objet est initialisé.std::__ostream_insert
, qui (comme vous l'avez déjà compris par le nom) est une méthode destd::cout
(essentiellement l'<<
opérateur) qui ajoute une chaîne au flux.cout::endl
est également passé àstd::__ostream_insert
.__std_dso_handle
est passé à__cxa_atexit
, qui est une fonction globale qui est responsable du «nettoyage» avant de quitter le programme.__std_dso_handle
lui-même est appelé par cette fonction pour désallouer et détruire les objets globaux restants.Donc utiliser C == ne paie rien?
Dans le code C, très peu d'étapes se produisent:
puts
via leedi
registre.puts
est appelé.Aucun objet nulle part, donc pas besoin d'initialiser / détruire quoi que ce soit.
Cela ne veut pas dire que vous n'êtes pas « payer » pour quoi que ce soit en C . Vous payez toujours pour l'abstraction, et l'initialisation de la bibliothèque standard C et la résolution dynamique de la
printf
fonction (ou, en faitputs
, qui est optimisée par le compilateur puisque vous n'avez besoin d'aucune chaîne de format) se produisent toujours sous le capot.Si vous deviez écrire ce programme en assemblage pur, il ressemblerait à ceci:
Ce qui aboutit essentiellement à l'invocation de l'appel
write
système suivi de l'exit
appel système. Maintenant, ce serait le strict minimum pour accomplir la même chose.Résumer
C est beaucoup plus simple et ne fait que le strict minimum nécessaire, laissant un contrôle total à l'utilisateur, qui est capable d'optimiser et de personnaliser complètement tout ce qu'il veut. Vous dites au processeur de charger une chaîne dans un registre, puis d'appeler une fonction de bibliothèque pour utiliser cette chaîne. Le C ++, quant à lui, est beaucoup plus complexe et abstrait . Cela présente un énorme avantage lors de l'écriture de code compliqué, et permet un code plus facile à écrire et plus convivial, mais cela a évidemment un coût. Il y aura toujours un inconvénient dans les performances en C ++ par rapport à C dans des cas comme celui-ci, car C ++ offre plus que ce qui est nécessaire pour accomplir ces tâches de base, et donc il ajoute plus de surcharge .
Répondre à votre question principale :
Dans ce cas précis, oui . Vous ne profitez pas de tout ce que C ++ a à offrir plus que C, mais c'est simplement parce qu'il n'y a rien dans ce simple morceau de code que C ++ pourrait vous aider: c'est si simple que vous n'avez vraiment pas besoin de C ++ du tout.
Oh, et encore une chose!
Les avantages de C ++ peuvent ne pas sembler évidents à première vue, puisque vous avez écrit un programme très simple et petit, mais regardez un exemple un peu plus complexe et voyez la différence (les deux programmes font exactement la même chose):
C :
C ++ :
J'espère que vous pouvez clairement voir ce que je veux dire ici. Notez également comment en C vous devez gérer la mémoire à un niveau inférieur en utilisant
malloc
etfree
comment vous devez faire plus attention à l'indexation et aux tailles, et comment vous devez être très spécifique lors de la saisie et de l'impression.la source
Il y a quelques idées fausses pour commencer. Premièrement, le programme C ++ ne donne pas 22 instructions, c'est plutôt 22 000 d'entre elles (j'ai tiré ce nombre de mon chapeau, mais c'est approximativement dans le ballpark). De plus, le code C ne donne pas non plus 9 instructions. Ce ne sont que ceux que vous voyez.
Ce que fait le code C, c'est qu'après avoir fait beaucoup de choses que vous ne voyez pas, il appelle une fonction du CRT (qui est généralement mais pas nécessairement présente en tant que bibliothèque partagée), puis ne vérifie pas la valeur de retour ou la poignée erreurs, et renfloue. Selon les paramètres du compilateur et d'optimisation, il n'appelle même pas vraiment
printf
maisputs
, ou quelque chose d'encore plus primitif.Vous auriez pu écrire plus ou moins le même programme (à l'exception de certaines fonctions d'initialisation invisibles) en C ++, si seulement vous appeliez cette même fonction de la même manière. Ou, si vous voulez être super correct, cette même fonction préfixée avec
std::
.Le code C ++ correspondant n'est en réalité pas du tout la même chose. Alors que l'ensemble
<iostream>
est bien connu pour être un gros cochon laid qui ajoute une énorme surcharge pour les petits programmes (dans un "vrai" programme, vous ne remarquez pas vraiment beaucoup), une interprétation un peu plus juste est qu'il fait un horrible beaucoup de choses que vous ne voyez pas et qui fonctionnent . Y compris, mais sans s'y limiter, le formatage magique de pratiquement tous les éléments aléatoires, y compris différents formats de nombres et paramètres régionaux, etc., ainsi que la mise en mémoire tampon et la gestion appropriée des erreurs. La gestion des erreurs? Eh bien oui, devinez quoi, la sortie d'une chaîne peut en fait échouer, et contrairement au programme C, le programme C ++ ne l' ignorerait pas en silence. Considérant quoistd::ostream
fait sous le capot, et sans que personne ne s'en rende compte, il est en fait assez léger. Pas comme si je l'utilisais car je déteste la syntaxe du flux avec passion. Mais quand même, c'est assez génial si vous considérez ce que cela fait.Mais bien sûr, C ++ dans son ensemble n'est pas aussi efficace que C peut l'être. Il ne peut pas être aussi efficace car il est pas la même chose et il ne fait la même chose. Si rien d'autre, C ++ génère des exceptions (et du code pour les générer, les gérer ou les échouer) et il donne des garanties que C ne donne pas. Donc, bien sûr, un programme C ++ doit nécessairement être un peu plus gros. Dans l'ensemble, cependant, cela n'a aucune importance. Au contraire, pour les vrais programmes, je n'ai pas rarement trouvé le C ++ plus performant car pour une raison ou une autre, il semble prêter des optimisations plus favorables. Ne me demandez pas pourquoi en particulier, je ne saurais pas.
Si, au lieu de feu-et-oubliez-l'espoir-pour-le-mieux, vous voulez écrire du code C qui est correct (c'est-à-dire que vous vérifiez réellement les erreurs et que le programme se comporte correctement en présence d'erreurs) alors la différence est marginale, s'il existe.
la source
std::cout
jette-t-il aussi des exceptions?std::cout
est unstd::basic_ostream
et que l'on peut lancer, et il peut renvoyer des exceptions se produisant autrement s'il est configuré pour le faire ou il peut avaler des exceptions. Le fait est que des choses peuvent échouer, et C ++ ainsi que la bibliothèque standard C ++ sont (principalement) construites afin que les échecs ne passent pas facilement inaperçus. C'est un ennui et une bénédiction (mais, plus de bénédiction que de contrariété). C d'autre part vous montre juste le majeur. Vous ne vérifiez pas un code de retour, vous ne savez jamais ce qui s'est passé.Vous payez pour une erreur. Dans les années 80, lorsque les compilateurs ne sont pas assez bons pour vérifier les chaînes de format, la surcharge des opérateurs était considérée comme un bon moyen d'imposer un semblant de sécurité de type pendant io. Cependant, chacune de ses fonctionnalités de bannière est soit mal implémentée, soit conceptuellement en faillite dès le début:
<iomanip>
La partie la plus répugnante du flux C ++ io api est l'existence de cette bibliothèque d'en-têtes de formatage. En plus d'être avec état, laid et sujet aux erreurs, il couple le formatage au flux.
Supposons que vous vouliez imprimer une ligne avec 8 chiffres zéro hexadécimal non signé int suivi d'un espace suivi d'un double avec 3 décimales. Avec
<cstdio>
, vous pouvez lire une chaîne de format concis. Avec<ostream>
, vous devez enregistrer l'ancien état, définir l'alignement à droite, définir le caractère de remplissage, définir la largeur de remplissage, définir la base sur hexadécimal, afficher l'entier, restaurer l'état enregistré (sinon votre formatage d'entier polluera votre formatage flottant), afficher l'espace , définissez la notation sur fixe, définissez la précision, sortez le double et la nouvelle ligne, puis restaurez l'ancien formatage.Surcharge de l'opérateur
<iostream>
est l'enfant de l'affiche de la façon de ne pas utiliser la surcharge d'opérateurs:Performance
std::cout
est plusieurs fois plus lentprintf()
. La fonctionnalité rampante et la répartition virtuelle font des ravages.Sécurité du fil
Les deux
<cstdio>
et<iostream>
sont thread-safe en ce que chaque appel de fonction est atomique. Mais,printf()
fait beaucoup plus par appel. Si vous exécutez le programme suivant avec l'<cstdio>
option, vous ne verrez qu'une ligne def
. Si vous utilisez<iostream>
sur une machine multicœur, vous verrez probablement autre chose.La réplique à cet exemple est que la plupart des gens exercent une discipline pour ne jamais écrire dans un seul descripteur de fichier à partir de plusieurs threads de toute façon. Eh bien, dans ce cas, vous devrez observer que cela
<iostream>
attirera utilement un verrou sur<<
chaque>>
. Alors que dans<cstdio>
, vous ne verrouillez pas aussi souvent, et vous avez même la possibilité de ne pas verrouiller.<iostream>
dépense plus de verrous pour obtenir un résultat moins cohérent.la source
std::cout
Est plusieurs fois plus lentprintf()
» - Cette affirmation est répétée partout sur le net, mais cela n'a pas été vrai depuis des lustres. Les implémentations IOstream modernes fonctionnent à égalité avecprintf
. Ce dernier effectue également un envoi virtuel en interne pour gérer les flux tamponnés et les E / S localisées (effectuées par le système d'exploitation mais néanmoins réalisées).printf
etcout
diminue. Soit dit en passant, il y a des tonnes de telles références sur ce même site.En plus de ce que toutes les autres réponses ont dit,
il y a aussi le fait que ce
std::endl
n'est pas la même chose que'\n'
.C'est une idée fausse malheureusement courante.
std::endl
ne signifie pas "nouvelle ligne",cela signifie "imprimer une nouvelle ligne et ensuite vider le flux ". Le rinçage n'est pas bon marché!
En ignorant complètement les différences entre
printf
etstd::cout
pendant un moment, pour être fonctionnellement équivalent à votre exemple C, votre exemple C ++ devrait ressembler à ceci:Et voici un exemple de ce à quoi vos exemples devraient ressembler si vous incluez le rinçage.
C
C ++
Lorsque vous comparez du code, vous devez toujours faire attention à ce que vous compariez comme pour le même et que vous compreniez les implications de ce que fait votre code. Parfois, même les exemples les plus simples sont plus compliqués que certains ne le pensent.
la source
std::endl
est l'équivalent fonctionnel de l'écriture d'une nouvelle ligne dans un flux stdio tamponné en ligne.stdout
, en particulier, doit être soit en tampon de ligne, soit sans tampon lorsqu'il est connecté à un dispositif interactif. Linux, je crois, insiste sur l'option tamponnée en ligne.std::endl
pour générer des nouvelles lignes.setvbuf(3)
? Ou voulez-vous dire que la ligne par défaut est tamponnée? FYI: Normalement, tous les fichiers sont mis en mémoire tampon. Si un flux fait référence à un terminal (comme le fait normalement stdout), il est mis en tampon en ligne. Le flux d'erreur standard stderr est toujours sans tampon par défaut.printf
vide pas automatiquement lorsque vous rencontrez un personnage de nouvelle ligne?Bien que les réponses techniques existantes soient correctes, je pense que la question découle en fin de compte de cette idée fausse:
Il ne s'agit que d'un discours marketing de la communauté C ++. (Pour être honnête, il y a des discussions marketing dans toutes les communautés linguistiques.) Cela ne signifie rien de concret sur lequel vous pouvez compter sérieusement.
«Vous payez pour ce que vous utilisez» est censé signifier qu'une fonctionnalité C ++ n'a de surcharge que si vous utilisez cette fonctionnalité. Mais la définition d '«une caractéristique» n'est pas infiniment granulaire. Souvent, vous finirez par activer des fonctionnalités qui ont plusieurs aspects, et même si vous n'avez besoin que d'un sous-ensemble de ces aspects, il n'est souvent pas pratique ou possible pour l'implémentation d'intégrer partiellement la fonctionnalité.
En général, de nombreuses langues (mais pas toutes) s'efforcent d'être efficaces, avec plus ou moins de succès. C ++ est quelque part sur l'échelle, mais il n'y a rien de spécial ou de magique dans sa conception qui lui permettrait de réussir parfaitement dans cet objectif.
la source
<cstdio>
et ne pas inclure<iostream>
, tout comme vous pouvez compiler avec-fno-exceptions -fno-rtti -fno-unwind-tables -fno-asynchronous-unwind-tables
.Les fonctions d'entrée / sortie en C ++ sont élégamment écrites et sont conçues pour être simples à utiliser. À bien des égards, ils sont une vitrine pour les fonctionnalités orientées objet en C ++.
Mais vous abandonnez effectivement un peu de performance en retour, mais c'est négligeable par rapport au temps mis par votre système d'exploitation pour gérer les fonctions à un niveau inférieur.
Vous pouvez toujours revenir aux fonctions de style C car elles font partie de la norme C ++, ou peut-être renoncer complètement à la portabilité et utiliser des appels directs à votre système d'exploitation.
la source
std::basic_*stream
baisse) connaît les maux de tête entrants. Ils ont été conçus pour être largement généraux et étendus par héritage; mais personne n'a finalement fait ça, en raison de leur complexité (il y a littéralement des livres écrits sur iostreams), à tel point que de nouvelles bibliothèques sont nées juste pour cela (par exemple, boost, ICU, etc.). Je doute que nous cesserions jamais de payer pour cette erreur.Comme vous l'avez vu dans d'autres réponses, vous payez lorsque vous créez des liens dans des bibliothèques générales et appelez des constructeurs complexes. Il n'y a pas de question particulière ici, plus un reproche. Je vais souligner quelques aspects du monde réel:
Barne avait un principe de conception de base pour ne jamais laisser l'efficacité être une raison de rester en C plutôt qu'en C ++. Cela dit, il faut être prudent pour obtenir ces gains d'efficacité, et il y a des gains d'efficacité occasionnels qui ont toujours fonctionné mais qui n'étaient pas «techniquement» dans la spécification C. Par exemple, la disposition des champs de bits n'était pas vraiment spécifiée.
Essayez de regarder à travers ostream. Oh mon dieu c'est gonflé! Je ne serais pas surpris de trouver un simulateur de vol là-dedans. Même printf () de stdlib tourne généralement autour de 50K. Ce ne sont pas des programmeurs paresseux: la moitié de la taille de printf était liée à des arguments de précision indirecte que la plupart des gens n'utilisent jamais. Presque chaque bibliothèque de processeur vraiment contrainte crée son propre code de sortie au lieu de printf.
L'augmentation de la taille offre généralement une expérience plus contenue et plus flexible. Par analogie, un distributeur automatique vendra une tasse de substance semblable à du café pour quelques pièces et toute la transaction prend moins d'une minute. Se rendre dans un bon restaurant implique de mettre une table, d'être assis, de commander, d'attendre, de prendre une bonne tasse, d'obtenir une facture, de payer dans votre choix de formes, d'ajouter un pourboire et de se faire souhaiter une bonne journée en sortant. C'est une expérience différente et plus pratique si vous passez avec des amis pour un repas complexe.
Les gens écrivent toujours ANSI C, bien que rarement K&R C. Mon expérience est que nous le compilons toujours avec un compilateur C ++ en utilisant quelques ajustements de configuration pour limiter ce qui est traîné. Il y a de bons arguments pour d'autres langages: Go supprime la surcharge polymorphe et le préprocesseur fou ; il y a eu de bons arguments pour un empaquetage de champ et une disposition de mémoire plus intelligents. IMHO Je pense que toute conception de langage devrait commencer par une liste d'objectifs, un peu comme le Zen de Python .
Ce fut une discussion amusante. Vous vous demandez pourquoi vous ne pouvez pas avoir de bibliothèques magiquement petites, simples, élégantes, complètes et flexibles?
Il n'y a pas de reponse. Il n'y aura pas de réponse. Voilà la réponse.
la source