web-dev-qa-db-fra.com

Écrire en C pour la performance?

Je sais que j'ai entendu assez souvent que C a généralement un avantage sur les performances par rapport à C++. Je n'ai pas vraiment pensé à autre chose jusqu'à ce que je réalise que MSVC ne semble même pas prendre en charge le plus récent standard de C, mais le plus récent qu'il prend en charge C99 (pour autant que je sache).

J'avais l'intention d'écrire une bibliothèque avec du code à rendre en OpenGL afin de pouvoir la réutiliser. J'avais l'intention d'écrire la bibliothèque en C car toute augmentation de performance est la bienvenue en ce qui concerne les graphiques.

Mais en vaudrait-il vraiment la peine? Le code utilisant la bibliothèque serait probablement écrit en C++ et je préfère coder en C++ en général.

Cependant, si cela produisait même une petite différence de performance, j'irais probablement avec C.

Il peut également être noté que cette bibliothèque serait quelque chose que je ferais pour fonctionner sous Windows/OS X/Linux, et je compilerais probablement tout nativement (MSVC pour Windows, Clang ou GCC pour OS X et GCC pour Linux .. . ou éventuellement des compilateurs Intel pour tout).

J'ai regardé autour de moi et j'ai trouvé des repères et autres, mais tout ce que j'ai vu concerne GCC plutôt que MSVC et Clang. De plus, les benchmarks ne mentionnent pas les standards des langages utilisés. Quelqu'un a un avis là dessus?

EDIT: Je voulais juste partager mon point de vue sur cette question après quelques années d'expérience. J'ai fini par écrire le projet pour lequel je posais cette question en C++. J'ai commencé un autre projet à peu près au même moment en C, alors que nous cherchions à obtenir la moindre quantité de performances possible et que le projet devait être lié en C.Il y a quelques mois, j'ai atteint le point où j'avais vraiment besoin de cartes et d'avancées. manipulation de chaînes. Je connaissais les capacités pour cela dans la bibliothèque standard C++ et suis finalement arrivé à la conclusion que ces structures dans la bibliothèque standard seraient probablement plus performantes et plus stables que les cartes et les chaînes que je pourrais implémenter en C dans un laps de temps raisonnable. L'exigence d'être liable en C a été facilement satisfaite en écrivant une interface C dans le code C++, ce qui a été fait rapidement avec des types opaques. La réécriture de la bibliothèque en C++ semblait aller beaucoup plus vite que lors de l'écriture en C et était moins sujette aux bugs, en particulier aux fuites de mémoire. J'ai également pu utiliser la bibliothèque de threading de bibliothèque standard, qui a été beaucoup plus facile que d'utiliser des implémentations spécifiques à la plate-forme. Au final, je pense que l'écriture de la bibliothèque en C++ a conduit à de grands avantages avec peut-être un faible coût de performance. Je n'ai pas encore testé la version C++, mais je pense qu'il est même possible que j'aie gagné en performances en utilisant des structures de données de bibliothèque standard que celles que j'ai écrites.

32
danielunderwood

Je suppose que les gens prétendent souvent que C est plus rapide que C++ parce qu'il est plus facile de raison sur les performances en C. C++ n'est pas intrinsèquement plus lent ou plus rapide, mais certains codes C++ peuvent masquer des pénalités de performances cachées. Par exemple, il peut y avoir des copies et des conversions implicites qui ne sont pas immédiatement visibles lorsque vous regardez un morceau de code C++.

Prenons la déclaration suivante:

foo->doSomething(a + 5, *c);

Supposons en outre que doSomething a la signature suivante:

void doSomething(int a, long b);

Maintenant, essayons d'analyser l'impact possible des performances de cette instruction particulière.

En C, les implications sont assez claires. foo ne peut être qu'un pointeur vers une structure et doSomething doit être un pointeur vers une fonction. *c Fait une longue référence et a + 5 Est une addition entière. La seule incertitude vient du type de a: Si ce n'est pas un int, il y aura une conversion. mais en dehors de cela, il est facile de quantifier l'impact sur les performances de cette seule déclaration.

Passons maintenant au C++. La même déclaration peut désormais avoir des caractéristiques de performances très différentes:

  1. doSomething pourrait être une fonction membre non virtuelle (bon marché), une fonction membre virtuelle (un peu plus chère), std::function, lambda ... etc. Pire encore, foo pourrait être une surcharge de type classe operator-> avec une opération d'une complexité inconnue. Ainsi, afin de quantifier le coût de l'appel de doSomething, il est maintenant nécessaire de connaître la nature exacte de foo et doSomething.
  2. a peut être un entier, ou une référence à un entier (indirection supplémentaire), ou un type de classe qui implémente operator+(int). L'opérateur pourrait même retourner un autre type de classe qui est implicitement convertible en int. Encore une fois, le coût de la performance ne ressort pas de la seule déclaration.
  3. c pourrait être un type de classe implémentant operator*(). Il peut également s'agir d'une référence à un long* Etc.

Vous obtenez l'image. En raison des fonctionnalités du langage C++, il est beaucoup plus difficile de quantifier les coûts de performance d'une seule instruction qu'en C. Maintenant, en outre, des abstractions comme std::vector, std::string Sont couramment utilisées en C++, qui ont caractéristiques de performances propres et masquer les allocations de mémoire dynamiques (voir également la réponse de @ Ian).

Donc, l'essentiel est: En général, il n'y a aucune différence dans les performances possibles réalisables en utilisant C ou C++. Mais pour le code vraiment critique pour les performances, les gens préfèrent souvent utiliser C car il y a beaucoup moins de pénalités de performance cachées .

89
lethal-guitar

Le code écrit en C++ peut être plus rapide qu'en C, pour certains types de tâches.

Si vous préférez C++, utilisez C++. Tous les problèmes de performances vont être insignifiants par rapport aux décisions algorithmiques de votre logiciel.

30
whatsisname

L'un des principes de conception de C++ est que vous ne payez pas pour des fonctionnalités que vous n'utilisez pas. Donc, si vous écrivez du code en C++ et évitez les fonctionnalités qui n'existent pas en C, le code compilé résultant devrait être équivalent en performances (bien que vous deviez le mesurer).

L'utilisation de classes, par exemple, est négligeable par rapport aux structures et à un tas de fonctions associées. Les fonctions virtuelles coûteront un peu plus, et vous devrez mesurer les performances pour voir si elles sont importantes pour votre application. Il en va de même pour toute autre fonctionnalité du langage C++.

23
Greg Hewgill

L'une des raisons pour lesquelles les langages de niveau supérieur sont parfois plus lents est qu'ils peuvent se cacher en coulisses beaucoup plus de gestion de mémoire que les langages de niveau inférieur.

Tout langage (ou bibliothèque, API, etc.) qui résume les détails de bas niveau peut potentiellement masquer des opérations coûteuses. Par exemple, dans certaines langues, le simple fait de supprimer les espaces de fin d'une chaîne entraîne une allocation de mémoire et une copie de la chaîne. L'allocation de mémoire et la copie en particulier peuvent coûter cher si elles se produisent à plusieurs reprises dans une boucle étroite.

Si vous écriviez ce type de code en C, ce serait flagrant. En C++ peut-être moins, car les allocations et la copie peuvent être résumées quelque part dans une classe. Ils peuvent même être cachés derrière un opérateur surchargé ou un constructeur de copie à l'air innocent.

Utilisez donc C++ si vous le souhaitez. Mais ne vous laissez pas séduire par l'apparente commodité des abstractions lorsque vous ne savez pas ce qui se cache en dessous.

Bien sûr, utilisez un profileur pour savoir ce qui ralentit vraiment votre code.

14
Ian Goldby

Pour ce que ça vaut, j'ai tendance à écrire mes bibliothèques en C++ 11 pour l'ensemble de fonctionnalités amélioré. J'aime pouvoir profiter de choses comme les pointeurs partagés, les exceptions, la programmation générique et d'autres fonctionnalités C++ uniquement. J'aime C++ 11 parce que j'ai trouvé qu'une bonne partie de celui-ci est prise en charge sur toutes les plates-formes qui m'intéressent. Visual Studio 2013 a beaucoup des fonctionnalités de langage de base et des implémentations de bibliothèque prêtes à l'emploi et travaille censément sur l'ajout du reste. Comme vous le savez, Clang et GCC prennent également en charge l'ensemble des fonctionnalités.

Cela dit, j'ai récemment lu une très bonne stratégie concernant le développement de bibliothèques qui, je pense, est directement pertinente pour votre requête. L'article est intitulé "Un style de gestion des erreurs C qui joue Nice avec des exceptions C++" Stefanu Du Toit se réfère à cette stratégie comme un modèle de "sablier". Le premier paragraphe de l'article:

J'ai écrit beaucoup de code de bibliothèque en utilisant ce que j'appelle un modèle de "sablier": j'implémente une bibliothèque (dans mon cas, généralement en utilisant C++), je l'enveloppe dans une API C qui devient le seul point d'entrée de la bibliothèque, puis encapsulez cette API C en C++ ou dans un ou plusieurs autres langages pour fournir une abstraction riche et une syntaxe pratique. En ce qui concerne le code natif multiplateforme, les API C offrent une stabilité ABI inégalée et une portabilité vers d'autres langues via les FFI. Je limite même l'API à un sous-ensemble de C qui, je le sais, est portable pour une grande variété de FFI et protège la bibliothèque des fuites de changements dans les structures de données internes - attendez-en plus à ce sujet dans les prochains articles de blog.


Maintenant, pour répondre à votre principale préoccupation: la performance.

Je dirais, comme beaucoup d'autres réponses ici, que l'écriture de code dans l'une ou l'autre langue fonctionnerait tout aussi bien du point de vue des performances. D'un point de vue personnel, je trouve que l'écriture de code correct en C++ est plus facile en raison des fonctionnalités du langage, mais je pense que c'est une préférence personnelle. Quoi qu'il en soit, les compilateurs sont vraiment intelligents et ont tendance à écrire un meilleur code que vous de toute façon. Cela signifie que le compilateur optimisera probablement votre code mieux que vous.

Je sais que beaucoup de programmeurs le disent, mais la première chose à faire est d'écrire votre code, puis de le profiler et de faire des optimisations là où votre profileur vous suggère de le faire. Votre temps sera beaucoup mieux utilisé pour produire des fonctionnalités, puis l'optimiser une fois que vous pourrez voir où se trouvent vos goulots d'étranglement.


Maintenant, pour quelques lectures amusantes sur la façon dont les fonctionnalités et les optimisations du langage peuvent vraiment fonctionner en votre faveur:

std :: unique_ptr a zéro surcharge

constexp permet le calcul au moment de la compilation

déplacer la sémantique empêche les objets temporaires inutiles

5
vmrob

La différence de performances entre C++ et C n'est pas due à quoi que ce soit dans le langage, à proprement parler, mais à ce qu'il vous incite à faire. C'est comme une carte de crédit contre de l'argent. Cela ne vous fait pas dépenser plus, mais vous le faites quand même, sauf si vous êtes très discipliné.

Voici un exemple d'un programme écrit en C++, qui a ensuite été agressivement optimisé pour les performances. Vous devez savoir comment effectuer un réglage agressif des performances, quelle que soit la langue. La méthode que j'utilise est une pause aléatoire, comme indiqué dans cette vidéo .

Les types de choses coûteuses que C++ vous tente de faire sont une gestion excessive de la mémoire, une programmation de style notification, la confiance de votre compteur de programme pour les bibliothèques d'abstraction à plusieurs couches (comme l'a dit @Ian), la dissimulation de la lenteur, etc.

4
Mike Dunlavey

C n'a aucun avantage en termes de performances par rapport à C++ si vous faites les mêmes choses dans les deux langages. Vous pouvez prendre n'importe quel ancien code C écrit par n'importe quel programmeur C décent et le transformer en code C++ valide et équivalent, qui s'exécutera tout aussi rapidement (à moins que vous et votre compilateur sachiez ce que fait le mot clé "restrict" et que vous l'utilisiez efficacement, mais la plupart des gens ne le font pas).

C++ peut avoir des performances extrêmement différentes, soit plus lentes ou plus rapides, si (1) vous utilisez la bibliothèque C++ standard pour faire des choses qui peuvent être faites beaucoup plus rapidement et plus facilement sans utiliser la bibliothèque, ou (2) si vous utilisez la bibliothèque C++ standard pour faire les choses beaucoup plus facilement et plus rapidement qu'en réimplémentant la bibliothèque en mauvais C.

2
gnasher729