C ++ est-il adapté aux systèmes embarqués?


168

Une question commune, ici et ailleurs. C ++ est-il adapté aux systèmes embarqués?

Des microcontrôleurs? RTOS? Grille-pain? PC intégrés?

La POO est-elle utile sur les microcontrôleurs?

C ++ supprime-t-il trop le programmeur du matériel pour être efficace?

Le C ++ d’Arduino (sans gestion de mémoire dynamique, modèles, exceptions) doit-il être considéré comme du "vrai C ++"?

(Espérons que ce wiki servira de lieu pour contenir cette guerre sainte potentielle)


5
Question rapide: quand vous dites embarqué , vous voulez dire microcontrôleur? microprocesseur? x86 intégré / PC intégré?
J. Polfer

1
Je n'avais pas l'intention de provoquer une guerre sainte; L'intention était d'apprendre quels étaient vos arguments contre elle.
J. Polfer

2
Cela a déjà été abordé dans plusieurs questions, alors j’ai pensé qu’un lieu central serait bien.
Toby Jaffey

4
C ++ vs embedded est un sujet controversé. J'ai une forte opinion, mais je ne pensais pas qu'il était juste de poser une question et de jouer des points. J'espère qu'un wiki de la communauté permettra une discussion plus équilibrée.
Toby Jaffey

13
C'est une mauvaise question, car "incorporé" est un attribut dépourvu de sens pour décider si une langue particulière et son bagage associé conviennent. Le problème est petit par rapport aux grands systèmes, où les petits systèmes n'exécutent pas un système d'exploitation, ont une mémoire limitée, ne sont peut-être pas von-Neuman, peuvent avoir diverses restrictions matérielles sur les piles d'appels, les piles de données, vous ne pouvez pas simplement allouer dynamiquement un Mo ou même un ko, etc. La plupart des microcontrôleurs sont des "petits" systèmes. Les ordinateurs à carte unique sont généralement intégrés, mais sont généralement des "grands" systèmes.
Olin Lathrop

Réponses:


135

Oui, le C ++ est toujours utile dans les systèmes embarqués. Comme tout le monde l’a dit, cela dépend toujours du système lui-même, comme si un uC 8 bits serait probablement un non-non dans mon livre, même s’il existe un compilateur et que certaines personnes le font (frémir). Il existe toujours un avantage à utiliser le C ++, même lorsque vous le réduisez à quelque chose comme "C +", même dans un monde micro de 8 bits. Qu'est-ce que je veux dire par "C +"? Je veux dire, n'utilisez pas new / delete, évitez les exceptions, évitez les classes virtuelles avec héritage, évitez éventuellement l'héritage ensemble, soyez très prudent avec les modèles, utilisez des fonctions inline au lieu de macros et utilisez des constvariables au lieu de #defines.

Je travaille à la fois en C et en C ++ dans des systèmes embarqués depuis plus de 10 ans maintenant, et mon enthousiasme juvénile pour le C ++ s’est définitivement dissipé en raison de problèmes réels qui ébranlent la naïveté de chacun. J'ai vu le pire de C ++ dans un système embarqué que je voudrais appeler "les programmeurs CS devenus fous dans un monde EE". En fait, c’est quelque chose sur lequel je travaille avec mon client pour améliorer cette base de code qu’ils ont parmi d’autres.

Le danger du C ++ réside dans le fait qu’il s’agit d’un outil très puissant qui ressemble beaucoup à une épée à deux tranchants qui peut vous couper le bras et la jambe si elle n’est pas éduquée et disciplinée correctement dans son langage et sa programmation générale. C ressemble plus à une épée à simple tranchant, mais toujours aussi forte. Avec C ++, il est trop facile d’obtenir des niveaux d’abstraction très élevés et de créer des interfaces obscurcies qui perdent toute signification à long terme, et ce en partie du fait de la flexibilité du C ++ dans la résolution du même problème avec de nombreuses fonctionnalités de langage différentes (modèles, OOP, procédures, etc.). RTTI, modèles POO +, surcharge, inlining).

J'ai terminé deux séminaires de 4 heures sur les logiciels embarqués en C ++, donnés par le gourou du C ++, Scott Meyers. Il a souligné certaines choses sur les modèles que je n'avais jamais envisagées auparavant et sur le fait qu'elles peuvent contribuer davantage à la création d'un code essentiel pour la sécurité. En bref, vous ne pouvez pas avoir de code mort dans un logiciel qui doit répondre à des exigences strictes en matière de code de sécurité. Les modèles peuvent vous aider à accomplir cela, car le compilateur crée uniquement le code dont il a besoin lors de l'instanciation des modèles. Cependant, il faut mieux connaître leur utilisation pour concevoir correctement cette fonctionnalité plus difficile à réaliser en C, car les lieurs ne permettent pas toujours d'optimiser le code mort.

Scott Meyers est un très grand partisan des modèles et de l'utilisation judicieuse de l'inline, et je dois dire que je suis toujours sceptique quant à l'idée de parler de modèles. J'ai tendance à les fuir, même s'il dit qu'elles ne devraient être appliquées que là où elles deviennent le meilleur outil. Il souligne également que C ++ vous donne les outils nécessaires pour créer de très bonnes interfaces, faciles à utiliser correctement et rendant difficile l’utilisation erronée. Encore une fois, c'est la partie difficile. Il faut atteindre un niveau de maîtrise en C ++ avant de pouvoir savoir comment appliquer ces fonctionnalités de la manière la plus efficace possible pour devenir la meilleure solution de conception.

La même chose vaut pour la programmation orientée objet. Dans le monde intégré, vous devez vous familiariser avec le type de code que le compilateur va cracher pour savoir si vous pouvez gérer les coûts d'exécution du polymorphisme d'exécution. Vous devez également être disposé à prendre des mesures pour prouver que votre conception respecte les délais impartis. Est-ce que cette nouvelle classe InterruptManager va rendre ma latence d'interruption trop longue? Il existe d'autres formes de polymorphisme qui peuvent mieux convenir à votre problème, telles que le polymorphisme en temps de liaison, ce que C peut également faire, mais C ++ peut le faire via le modèle de conception Pimpl (pointeur Opaque) .

Je dis cela pour dire que le C ++ a sa place dans le monde embarqué. Vous pouvez détester tout ce que vous voulez, mais cela ne va pas disparaître. Il peut être écrit de manière très efficace, mais il est plus difficile d’apprendre à le faire correctement qu'avec C. Cela peut parfois être plus efficace que C pour résoudre un problème et parfois exprimer une meilleure interface, mais encore une fois, vous devez Renseignez-vous et n'ayez pas peur d'apprendre comment.


1
Cela va dans le sens de ce que j'ai lu d'autres consultants en systèmes intégrés. On m'a toujours enseigné qu'avec C, on se coupait constamment, mais un bug en C ++ va être plus rare, mais quand vous bousillez, vous allez perdre une jambe. Merci d'avoir écrit une réponse claire avec une expertise que je n'ai pas.
Kortuk

3
Sur la note des majors en informatique qui deviennent fous en EE Land. Dans mon travail, le pire code que nous ayons été écrit par un commandant de CS. Nous avons passé une éternité à essayer de lui apprendre le matériel. Il a créé un système structuré en utilisant UML et a construit le système dans son intégralité en java en utilisant un héritage approprié, etc. Cela a fonctionné, jusqu'à ce que quelque chose change, et ensuite l'ajout de fonctionnalités ou une refonte complète constituait un mauvais travail de patch. Le code n'est presque pas utilisable à cause de la profondeur avec laquelle il a obscurci le tout avec héritage.
Kortuk

2
Ce ne sont pas seulement les insectes qui vous piquent, mais le code intempestif qui vous piquera aussi. Bien sûr, lorsque vous démarrez ce projet en utilisant ces fonctionnalités C ++ ordonnées, tout se passe à merveille, mais après 2 ou 3 ans, l'entropie se déclenche si aucun effort sérieux n'est déployé dans le refactoring à mesure que vous développez. C’est ce à quoi je suis confronté en ce moment. Le code pourrit plus rapidement avec le temps en C ++.
Jay Atkinson

2
UML et machines à statuer. Vous devez vraiment vous renseigner sur l' état de Miro Samek sur state-machine.com . Il a mis au point un système efficace, facile à modifier et à modifier, mais il faut un certain temps pour le maîtriser.
Jay Atkinson

2
Cela dépend vraiment de votre système et de la quantité de mémoire disponible. Vous écrivez du code sur un micro 8 bits avec très peu de RAM? Vous feriez peut-être mieux d'éviter de devenir fou sur des interfaces abstraites. Si vous écrivez quelque chose comme des systèmes embarqués 32 bits avec des dalles de mémoire, foncez. Vous devez vraiment peser. Par exemple, chaque fois que vous collez le monde "virtuel" sur cette classe, vous obtenez un pointeur supplémentaire, qui peut être de 8 bits, de 16 bits ou de 32 bits selon le système, pour chaque instance que vous déclarez de cet objet. Vous ne réaliserez même pas, et mec,
Jay Atkinson

56

C ++ convient parfaitement aux systèmes embarqués. J'utilise maintenant la présence / l'absence de bons outils de développement (ou leur absence) comme critère principal pour utiliser ou non un microprocesseur particulier.

Les zones de C ++ qui sont bonnes à utiliser sur les systèmes embarqués, car leurs coûts de ressources sont faibles:

  • modularité apportée par un bon usage des classes / structures
  • gabarits si le compilateur les compile efficacement. Les modèles sont un bon outil pour réutiliser des algorithmes sur différents types de données.

Zones OK:

  • Fonctions virtuelles - J'y étais auparavant, mais le coût des ressources est très faible (une table virtuelle par classe et non par objet; un pointeur sur la table virtuelle par objet; une opération de déréférencement par appel de fonction virtuelle) et le grand avantage de cette c’est que cela vous permet d’avoir un tableau contenant plusieurs types d’objets sans savoir de quel type ils sont. J'ai utilisé cela récemment pour avoir un tableau d'objets représentant chacun un périphérique I2C, chacun avec des méthodes distinctes.

Zones à ne pas utiliser, principalement en raison de la surcharge d'exécution qui est inacceptable sur les petits systèmes:

  • allocation de mémoire dynamique - d'autres l'ont déjà mentionné, mais une autre raison importante de ne pas utiliser l'allocation de mémoire dynamique est qu'elle représente une incertitude dans le temps; De nombreuses raisons d'utiliser des systèmes intégrés sont destinées aux applications en temps réel.
  • RTTI (informations de type à l'exécution) - le coût en mémoire est plutôt élevé
  • exceptions - une certaine non-non, à cause du coup de vitesse d'exécution

Merci pour la contribution. Intéressant et très similaire à ce que j'ai lu.
Kortuk

1
En réalité, l’allocation de mémoire dynamique est correcte et parfois inévitable. C'est le problème de la mémoire dynamique DEallocation (et de sa réutilisation ultérieure). RTTI, c'est de la mémoire, je suis d'accord sur ça. Mais quel est le problème avec les exceptions?
Wouter van Ooijen

1
@WoutervanOoijen: Le problème avec les exceptions est que si les fooappels bardans un bloc try/ créent des objets et des appels , ce qui génère une exception, le système doit en quelque sorte appeler les destructeurs pour les objets créés avant de rendre le contrôle . À moins que les exceptions ne soient complètement désactivées, vous ne pourrez pas savoir si vous pouvez en lancer une, et vous devez donc inclure du code supplémentaire pour permettre cette possibilité. J'aimerais voir une variante du C ++ avec des "exceptions vérifiées" pour gérer cela; si des routines qui pourraient permettre aux exceptions de s'échapper ...catchbarbozbarfoobarboz
Supercat

1
... doit être déclaré en tant que tel, il suffirait alors que le compilateur inclue un code de traitement des exceptions dans les appelants de telles routines. Certes, avoir à ajouter toutes les déclarations requises, tout en évitant, espérons-le, des déclarations inutiles, serait quelque peu pesant, mais permettrait d’utiliser des exceptions dans des endroits où elles sont utiles, sans alourdir les tâches là où elles ne le sont pas.
Supercat

3
@WoutervanOoijen: Incidemment, si je concevais ABI pour une telle gestion des exceptions sur l’ARM, je spécifierais le code qui appelle une routine susceptible de sortir par exception devrait avoir R14 pointant deux octets avant l’adresse de retour souhaitée (cela se produit naturellement si l'appelant a suivi l'instruction CALL avec un mot de 16 bits). La routine appelée quitterait alors normalement via add r15,r14,#2au lieu de mov r15,r14; pour sortir par l' intermédiaire d' exception, ldrhs r0,[r14] / add r15,r14,r0. Coût de cycle nul pour la sortie normale et aucune restriction de trame de pile.
Supercat

36

Oui, C ++ est certainement adapté aux systèmes embarqués. Commençons par clarifier quelques idées fausses sur la différence entre C et C ++:

Dans un micro intégré, vous aurez toujours besoin d'utiliser des langages de haut niveau avec précaution si vous vous préoccupez de contraintes de temps ou d'espace. Par exemple, de nombreux MCU ne gèrent pas bien les pointeurs et sont donc très inefficaces lors de l'utilisation de la pile. Cela signifie que vous devez faire attention à ne pas transmettre de variables à des fonctions, à l'aide de tableaux et de pointeurs, et à la récursivité. Une simple ligne de C comme:

a[i] = b[j] * c[k];

peut générer environ 4 pages d’instructions en fonction de la nature de ces variables.

Chaque fois que vous utilisez un langage de haut niveau et que vous vous préoccupez de contraintes de temps et d'espace, vous devez savoir comment chaque fonctionnalité de cette langue se traduit par des instructions machine sur votre MCU (au moins, chaque fonctionnalité que vous utilisez). Ceci est vrai pour C, C ++, Ada, peu importe. Toutes les langues contiendront probablement des fonctionnalités qui ne traduiront pas efficacement sur les petites MCU. Vérifiez toujours les listes de désassemblage pour vous assurer que le compilateur ne génère pas une quantité d'instructions pour quelque chose de trivial.

C convient-il aux MCU intégrés? Oui, tant que vous gardez un œil sur le code généré.
C ++ est-il adapté aux MCU intégrés? Oui, tant que vous gardez un œil sur le code généré.

Voici pourquoi je pense que le C ++ est meilleur que le C même sur les MCU 8 bits: C ++ offre un support amélioré pour:

  • Cacher des données
  • Taper / vérifier plus fort
  • Transparence multi-périphérique à l'aide de classes
  • Modèles (comme toujours si utilisés avec précaution)
  • Listes d'initialisation
  • const

Aucune de ces caractéristiques n’est plus lourde que les caractéristiques typiques de C.

Lorsque vous déplacez des MCU 16 ou 32 bits, il devient logique d'utiliser des fonctionnalités plus lourdes de C (pile, tas, pointeurs, tableaux, printf, etc.). De la même manière, un MCU plus puissant devient approprié utiliser des fonctionnalités plus lourdes de C ++ (pile, tas, références, STL, nouveau / supprimer).

Donc, inutile de frémir à la pensée de C ++ sur un PIC16. Si vous connaissez bien votre langue et votre MCU, vous saurez les utiliser efficacement.


3
C'est une réponse très bien exprimée et raisonnable à la question. +1 a la vôtre!
vicatcu

1
" a[i] = b[j] * c[k];peut générer environ 4 pages d'instructions en fonction de la nature de ces variables." Si votre MCU / compilateur le fait, c'est que vous utilisez un processeur amateur de garage des années 80.
Lundin

@ Lundin - Soupir. Non, cela signifie que vous utilisez un petit MCU bon marché, conçu pour être aussi petit et aussi économique que possible, et non pour avoir des tâches complexes telles que l'indexation de pile.
Rocketmagnet

2
@ Rocketmagnet Ok peut-être dans les années 1990? De nos jours, 8 bitters merdiques viennent au même prix qu'un 32 bitters. La seule raison qui reste pour choisir le premier est la consommation actuelle. Et en ce qui concerne ces 8-bitters extra-merdiques sans pile: si vous écrivez C au lieu d’assembler pour un MCU aussi limité, vous ferez probablement une erreur. Les 4 pages générées sont alors votre propre faute pour l’écriture de programmes trop complexes pour la CPU, et C n’est vraiment pas le bon outil pour la tâche. (Je l'avais déjà fait par le passé sur Freescale RS08, c'était une idée très stupide.)
Lundin

@Lundin Un processeur 32 bits n’est pas nécessaire plus vite que 16 bits. Cela était évident à l'époque où la transition du programme 16 bits à 32 bits était en cours dans le monde des ordinateurs personnels.
Barleyman

24

Je trouve toujours ces débats divertissants à lire. Pas tant pour la discussion intellectuelle sur les avantages et les inconvénients des différentes langues disponibles, mais parce que vous pouvez généralement déterminer la position de quelqu'un sur le sujet en fonction de son travail, de son expérience ou de son domaine d'intérêt. Les arguments de «l'optimisation prématurée» sont à la hauteur des arguments avancés par les majors CS et les programmeurs de maintenance citant Knuth à gauche et à droite et par ceux qui travaillent dans le monde réel où la performance compte pour être fous (je suis membre de ce dernier groupe être juste).

À la fin de la journée, vous pouvez développer un excellent logiciel en C ou C ++ ou insérer un langage ici . Cela dépend des capacités du développeur et non du langage. Etre un expert dans une langue n’est généralement requis que si vous avez choisi la mauvaise langue pour commencer et que vous devez maintenant l’inciter à résoudre votre problème. Dans la plupart des cas, il s’agit là des seules situations dans lesquelles vous devez plonger dans des fonctionnalités obscures ou un compilateur. astuces pour atteindre l'objectif.

J'entends souvent les gens commencer ces arguments comme "Je suis un expert en langage X et bla bla" Je discrédite honnêtement immédiatement ces gens car, à mon avis, ils ont déjà abordé le problème sous le mauvais angle et tout ce qui a ensuite été corrompu. par leur désir d'utiliser leur outil pour résoudre le problème et montrer à quel point il est 'cool'.

Je vois souvent les développeurs choisir un ensemble d’outils d’abord et tenter de le résoudre ensuite, ce qui est complètement faux et donne lieu à des solutions merdiques.

Comme je l'ai mentionné dans un commentaire à une autre réponse, ces guerres linguistiques se résument souvent en argumentant que la langue X permet au programmeur de faire plus de bêtises. Bien que divertissantes à lire, toutes ces affirmations signifient vraiment que vous avez un problème pour engager de bons développeurs et que vous devez vous attaquer directement à ce problème plutôt que d'essayer de résoudre le problème en continuant à embaucher de mauvais développeurs et en choisissant des outils tels qu'ils puissent faire aussi bien. dommage possible.

À mon avis, les bons développeurs, qu'il s'agisse de développement de logiciels ou de matériel informatique, recherchent le problème, élaborent une solution et trouvent les outils qui leur permettent d'exprimer la solution de la "meilleure façon". Peu importe que l'outil requis soit quelque chose que vous n'ayez jamais utilisé auparavant. Après avoir utilisé 3-4 langages / outils de développement pour des projets, en choisir un nouveau devrait avoir un impact minimal sur votre temps de développement.

Bien entendu, le «meilleur moyen» est un terme subjectif et doit également être défini au cours de la phase de recherche. Il faut prendre en compte une multitude de problèmes: performances, facilité d’expression, densité du code, etc. en fonction du problème rencontré. Je n'ai pas inclus la maintenabilité dans cette liste pour une raison quelconque, peu importe la langue que vous choisissez, si vous avez choisi l'outil approprié et pris le temps de comprendre le problème, cela devrait venir «gratuitement». La difficulté de maintenir le code est souvent le résultat du choix d’un mauvais outil ou d’une structure de système médiocre. Il en résulte un désordre odieux pour le faire fonctionner.

Revendiquer n'importe quelle langue est "meilleure" que n'importe quelle autre est stupide sans définir un problème d'intérêt particulier. Une approche orientée objet n'est pas toujours meilleure qu'une approche fonctionnelle. Certains problèmes se prêtent très bien à un paradigme de conception orienté objet. Beaucoup ne le font pas. La même déclaration peut être faite à propos de nombreuses fonctionnalités linguistiques que les gens semblent aimer utiliser.

Si vous passez plus de 20% de votre temps à résoudre un problème de saisie de code, vous produisez probablement un système très médiocre ou des développeurs très médiocres (ou vous êtes encore en train d'apprendre). Vous devriez consacrer la majeure partie de votre temps au début à schématiser le problème et à déterminer les interactions entre différents éléments de l'application. Coller un groupe de développeurs talentueux dans une salle avec un marqueur et un problème à résoudre et leur dire qu’ils ne sont pas autorisés à écrire du code ou à choisir des outils tant qu’ils ne sont pas à l’aise avec le système tout entier en fera plus pour améliorer la qualité des fichiers. développement de la production et de la vitesse que le choix de tout nouvel outil chaud garanti pour améliorer le temps de développement. (regardez le développement de Scrum comme référence pour le contraire opposé à mon argument)

Souvent, la triste réalité est que beaucoup d'entreprises ne peuvent mesurer la valeur d'un développeur que par le nombre de lignes écrites ou par la «production tangible». Ils considèrent les 3 semaines passées dans une pièce avec un tableau comme une perte de productivité. Les développeurs sont souvent obligés d'accélérer le stade de développement de la "pensée" ou d'utiliser un outil défini par un problème politique au sein de l'entreprise: "Le frère de mon patron travaille pour IBM afin que nous ne puissions utiliser que leurs outils", ce genre de déchets. . Ou pire, vous obtenez un ensemble d'exigences en constante évolution de la part de l'entreprise, qui n'est pas en mesure de réaliser une étude de marché adéquate ou qui ne comprend pas l'impact des changements sur le cycle de développement.

Désolé d’être un peu en marge de ce discours, j’ai des opinions bien arrêtées sur ce sujet.


2
À présent, je ne déclenche pas de tests unitaires au niveau de l'application (au-dessus du pilote) sur certains systèmes embarqués. La rétroaction instantanée des tests unitaires et de la suppression des bogues au début de la phase de développement présente un intérêt particulier, mais le paradigme de la TDD dans son ensemble pour donner naissance à la conception me semble un peu dérangé. Je préfère prendre le temps de "réfléchir" au problème et de le représenter dans ma tête, sur papier ou sur un tableau blanc, avant de commencer à coder. Je pense également que TDD encourage le marché à ne pas effectuer de recherche préliminaire sur les exigences, car il est censé contribuer à un changement constant des exigences.
Jay Atkinson

2
Et pour mettre une note finale sur mon commentaire très long. Nous n’avons pas besoin d’experts en langue pour travailler le design. Nous avons besoin de designers experts capables de travailler la ou les langues.
Jay Atkinson

1
PRD = document d'exigences de produit, MRD = document d'exigences de marketing, TRD = document d'exigences techniques. TDD = Test Driven Development.
Jay Atkinson

1
@ Mark - Je suis d'accord avec vos sentiments d'avant la conception, mais seulement sur un point. Je pense que les travaux de conception en amont sont payants si a) vos exigences sont relativement stables / connues et b) que les développeurs chargés de la conception ont de l' expérience . Dans un prev. Au travail, j’ai été chargé de faire un dessin et celui-ci était encombré par le responsable de mon équipe, et j’ai pensé: "Quelle chose stupide à faire! La conception à l’avance permet d’économiser de l’argent (cf. Livre Code Complete) ??" Mais en codant, j'ai découvert des tonnes de choses que je ne savais pas chercher. Si j'avais fait beaucoup de conception et minimisé le temps de code, cela aurait été une perte de temps. JME.
J. Polfer

1
@sheepsimulator Je suis évidemment d'accord sur le deuxième point, je suppose que les architectes système principaux sont des développeurs expérimentés. Sur le premier point, je suis en désaccord. Je pense que plus vous vous attendez à ce que les exigences changent, plus vous devez passer de temps en phase de conception, car vous devez produire une conception de qualité, facile à modifier. Je sais que certaines philosophies proposent un développement rapide. Dans certains cas, cela fonctionne bien comme beaucoup de programmeurs mauvais ou inexpérimentés parmi le personnel. Toutes ces philosophies de conception se résument à dire "je n’ai aucune prière de concevoir un système flexible, alors ne perdons pas de temps à essayer".
Mark

17

Toute langue peut convenir à un système intégré. Embedded signifie simplement: fait partie d'un appareil plus volumineux, par opposition à un ordinateur libre d'utilisation.

La question a plus de pertinence lorsqu'on lui demande un système (en temps réel) ou à ressources limitées .

Pour un système temps réel, le langage C ++ est l’un des langages les plus élevés qui soit toujours approprié lors de la programmation pour des contraintes de temps strictes. À l'exception de l'utilisation de tas (opérateur libre), il n'a pas de construction dont le temps d'exécution est indéterminé. Vous pouvez donc vérifier si votre programme remplit ses exigences de synchronisation. Avec un peu plus d'expérience, vous pourriez même le prédire. Bien entendu, il convient d'éviter l'utilisation de tas, bien que le nouvel opérateur puisse toujours être utilisé pour une attribution unique. Les constructions que C ++ offre sur C peuvent être utilisées à bon escient dans un système embarqué: OO, exceptions, templates.

Pour les systèmes très limités en ressources (puces 8 bits, moins de quelques ko de RAM, pas de pile accessible), le C ++ complet pourrait ne pas convenir, bien qu'il puisse tout de même être utilisé comme "meilleur C".

Je pense qu'il est regrettable qu'Ada ne soit utilisé que dans certaines niches. À bien des égards, il s'agit d'un Pascal ++, mais sans la charge d'être compatible vers le haut avec un langage qui était déjà un véritable gâchis. (edit: le désordre sérieux est bien sûr que C. Pascal est un langage beau mais quelque peu impraticable.)

=============================================== ==============

EDIT: Je tapais une réponse à une nouvelle question ("Dans quels cas le C ++ est-il nécessaire lorsque nous programmons des microcontrôleurs"?) Qui était fermé en référence à celui-ci, je vais donc ajouter ce que j’ai écrit:

Il n'y a jamais de raison absolue d'utiliser un langage de programmation, mais il peut y avoir des arguments qui ont plus ou moins de poids dans une situation donnée. Les discussions à ce sujet peuvent être trouvées à de nombreux endroits, avec des positions allant de "ne jamais utiliser le C ++ pour un micro-contrôleur" à "toujours utiliser le C ++". Je suis plus avec la dernière position. Je peux donner quelques arguments, mais vous devrez décider vous-même quel poids ils ont dans une situation donnée (et dans quelle direction).

  • Les compilateurs C ++ sont plus rares que les compilateurs C; pour certaines cibles (par exemple les PIC 12 et 14 bits), il n’existe aucun compilateur C ++.
  • Les (bons) programmeurs C ++ sont plus rares que les (bons) programmeurs C, en particulier parmi ceux qui maîtrisent également (quelque peu) l'électronique.
  • C ++ a plus de constructions que C qui ne conviennent pas aux petits systèmes (comme les exceptions, RTTI, utilisation fréquente du tas).
  • C ++ a un ensemble de bibliothèques (standard) plus riche que C, mais une conséquence du point précédent est que les bibliothèques C ++ utilisent souvent des fonctionnalités inappropriées pour les petits systèmes et ne sont donc pas utilisables sur les petits systèmes.
  • C ++ a plus de constructions que C qui vous permettent de vous tirer une balle dans le pied.
  • C ++ a plus de constructions que C qui vous permettent de vous empêcher de vous tirer une balle dans le pied (oui, ceci est vrai pour l'OMI et le précédent).
  • Le C ++ possède un ensemble plus riche de mécanismes d'abstraction, ce qui permet de meilleures méthodes de programmation, en particulier pour les bibliothèques.
  • Les fonctionnalités du langage C ++ (constructeurs / destructeurs, fonctions de conversion, par exemple) compliquent la tâche de voir dans le code la machine générée et donc le coût en espace et en temps d'une construction de langage.
  • La construction du langage C ++ rend moins nécessaire de savoir exactement comment ils sont traduits en code machine car ils font "la bonne chose" d'une manière plus abstraite.
  • Le standard de langage C ++ évolue rapidement et est adopté rapidement par les grands compilateurs (gcc, clang, microsoft). C évolue plutôt mal, et l’adoption de certaines nouvelles fonctionnalités (variantes de tableaux) est inquiétante et a même été annulée dans une norme ultérieure. Ce point en particulier est intéressant en ce que différentes personnes l'utilisent pour soutenir les positions opposées.
  • Le C ++ est sans aucun doute un outil plus précis que le C. Confiez-vous vos programmeurs (ou vous-même) pour utiliser un tel outil afin de réaliser une belle sculpture, ou craignez-vous qu’ils se blessent et préféreriez-vous vous contenter d’un produit moins beau mais présentant moins de risques? ? (Je me souviens que mon professeur de sculpture m'a dit un jour que les outils émoussés pouvaient parfois être plus dangereux que les outils tranchants.)

Mon blog a quelques écrits sur l'utilisation de C ++ sur de petits systèmes (= micro-contrôleurs).


15

D'après mon expérience, C ++ est généralement mal adapté aux petits systèmes embarqués. Je veux dire par microcontrôleurs et périphériques sans système d'exploitation.

De nombreuses techniques de programmation orientée objet C ++ reposent sur une allocation de mémoire dynamique. Cela fait souvent défaut dans les petits systèmes.

STL et Boost démontrent réellement la puissance du C ++, les deux étant extrêmement volumineux.

C ++ encourage le programmeur à faire abstraction de la machine, où elle doit être adoptée dans les systèmes contraints.

L'année dernière, j'ai porté un produit commercial de bureau à distance sur des téléphones mobiles. Il a été écrit en C ++ et fonctionnait sous Windows, Linux et OSX. Mais il s’appuyait fortement sur les exceptions STL, la mémoire dynamique et C ++. Pour réussir sur les environnements WinCE, Symbian et sans système d'exploitation, une réécriture en C était l'option la plus saine.


Je suis d'accord en ce qui concerne les petits systèmes, mais je pense que nous avons des définitions différentes des petits systèmes. Lorsque vous avez 1 Ko de ROM et que du code C bien écrit prend tout un octet de ROM sauf un, c'est un petit système.
Kortuk

6
Je ne dis pas que C ne peut pas avoir une empreinte plus petite, mais vous auriez pu utiliser le C ++ et obtenir un résultat très similaire pour la conception de ce que nous venons de décrire. Je pense que le problème est que la plupart des programmeurs de programmation orientée objet sont habitués aux systèmes avec mémoire dynamique et utilisant des constructions très inefficaces, ce qui entraîne un code totalement inutile pour les systèmes à faible consommation.
Kortuk

4
Donc, ce que vous dites, c'est que vous ne voulez pas utiliser le C ++, vous voulez utiliser quelque chose entre le C et le C ++ (appelons-le simplement C +?). Dans ce cas, je suis d’accord, il y a beaucoup de conneries en C ++ que les gens utilisent simplement parce qu’ils sont disponibles, pas parce que c’est optimal. Presque toutes les langues sont capables de produire un bon code rapide, c'est une question d'utilisation. La plupart des guerres saintes pour les langues ne sont pas le résultat de leurs capacités, mais un argument sur la facilité avec laquelle un idiot peut faire des choses idiotes, ce qui est vraiment un argument idiot: p
Mark

2
"La plupart des guerres saintes pour les langues ne sont pas le résultat de leurs capacités, mais un argument sur la facilité avec laquelle un idiot peut faire des choses idiotes, ce qui est vraiment un argument idiot." Était une phrase très agréable. J'ai besoin de votre nom de famille pour pouvoir citer celui-ci.
Kortuk

1
Je n'utilise vraiment pas la mémoire dynamique en C non plus. Il n'y a nulle part que je dois l'avoir. À long terme, j'ai lu que cela peut devenir très très segmenté et commencer à causer des problèmes. Je dois avoir des cas très clairement conçus pour manquer de mémoire et pouvoir contrôler exactement combien il en reste.
Kortuk

11

J'espère ajouter plus de lumière que de chaleur à cette discussion sur le C ++ sur des systèmes nus et à ressources limitées.

Problèmes en C ++:

  • Les exceptions sont particulièrement un problème de RAM car le "tampon d'urgence" requis (où l'exception de mémoire insuffisante va par exemple) peut être plus grand que la RAM disponible et constitue certainement un gaspillage pour les microcontrôleurs. Pour plus d'informations, voir n4049 et n4234 . Ils doivent être désactivés (comportement non spécifié pour le moment, assurez-vous de ne pas les jeter). Le SG14 travaille actuellement sur de meilleurs moyens de le faire.

  • RTTI ne vaut probablement jamais la surcharge, il devrait être désactivé

  • De grandes versions de débogage, bien que cela ne pose pas de problème dans le développement de bureau classique, si le débogage ne tient pas sur la puce, cela peut poser problème. Le problème provient du code basé sur un modèle ou des appels de fonction supplémentaires ajoutés pour plus de clarté. Ces appels de fonctions supplémentaires seront à nouveau supprimés par l'optimiseur et la clarté ou la flexibilité supplémentaires peuvent constituer un avantage considérable. Toutefois, cela peut poser problème dans les versions de débogage.

  • Allocation de tas. Bien que la STL permette l'utilisation d'allocateurs personnalisés, cela peut être complexe pour la plupart des programmeurs. L'allocation de segment de mémoire est non déterministe (c.-à-d. Pas en temps réel difficile) et la fragmentation peut entraîner des situations inattendues de mémoire insuffisante malgré le travail effectué dans les tests. La tenue de livres nécessaire au tas afin de garder trace de l’espace libre et de la taille variable peut poser problème avec les petits objets. Il est généralement préférable d’utiliser l’allocation de pool (en C et C ++), mais cela peut être anormal pour les programmeurs C ++ habitués à utiliser uniquement le tas.

  • Le polymorphisme à l'exécution et les autres appels indirects sont généralement un gros problème de performances. Le problème est généralement davantage dû au fait que l'optimiseur ne peut pas voir au-delà d'eux davantage que l'extraction et le saut réels à l'adresse. Pour cette raison, les appels indirects doivent être évités en C et C ++ où, comme en C ++, ils sont plus enracinés dans la culture (et sont très utiles dans d'autres domaines).

  • l'interfaçage implicite avec Clib peut être problématique. Il peut sembler contre-intuitif que les problèmes de clib appartiennent à la catégorie C ++, mais le problème provient du partage implicite de ressources dans des environnements concurrents (le partage est plus explicite en C). L’utilisation de l’implémentation newLib courante entraîne souvent beaucoup de problèmes, ce qui n’est généralement pas nécessaire dans les UC, par contre newLibNanno n’est pas réentrant, de sorte que son accès doit être sérialisé (simplifié ici). C'est un problème pour C aussi mais l'accès est plus explicite. En règle générale, vous ne devez en principe utiliser rien de namespace std dans le contexte ISR, à moins que vous ne soyez sûr qu'il n'accède pas à l'état dans clib (errorno ou le tas, par exemple). C'est également important si vous utilisez des threads (je préfère RTC) pour remplacer new et delete afin de synchroniser l'accès à malloc et free.

En conclusion, C ++ a quelques problèmes mais ils sont essentiellement tous réparables ou évitables.

Maintenant pour C, ici le problème est d'ordre supérieur. Je n’ai pas la capacité syntaxique en C d’abstraire les choses de manière à pouvoir optimiser ou vérifier les invariants au moment de la compilation. Par conséquent, je ne peux pas encapsuler correctement des éléments de manière à ce que l'utilisateur n'ait pas besoin de savoir comment ils fonctionnent pour pouvoir les utiliser et la plupart de mes erreurs sont détectées à l'exécution (ce qui est non seulement trop tard, mais entraîne également des coûts supplémentaires). La seule façon d'être générique en C est de passer par les données. Je passe une chaîne de format à printf ou scanf, qui est évaluée au moment de l'exécution, par exemple. Il est alors assez difficile pour le compilateur de prouver que je n'utilise pas certaines des options théoriquement possibles lorsque les bonnes données sont transmises, ce qui signifie une génération potentielle de code mort et une perte de potentiel d'optimisation.

Je sais que je suis peut-être en train de déchaîner une merde ici, mais mon expérience des microcontrôleurs 32 bits est que dans une comparaison de pommes à pommes de C et C ++ écrits par des experts (comme en C ++, potentiellement très basés sur des modèles), C ++ est le langage beaucoup plus efficace dès que tout doit être générique (comme dans n'importe quelle bibliothèque) et ils sont essentiellement équivalents dans des cas non génériques. Il est également plus facile pour un novice de tirer parti de l’expertise d’un développeur expert de bibliothèques en C ++.

En même temps, il y a vraiment vraiment peu de fonctions pour lesquelles je ne peux pas transmettre de données incorrectes, dès que l'entrée n'est pas un int, mais somethingpour lequel j'utilise un int comme méthode de représentation, il y a un potentiel pour l'obtenir faux (passe une valeur invalide ou un "otherThing" plutôt qu'un "quelque chose"). En C, ma seule méthode pour vérifier si l'utilisateur s'est trompé est au moment de l'exécution. En C ++, j'ai la possibilité d'effectuer certaines vérifications, pas toutes, mais certaines vérifications au moment de la compilation, qui sont gratuites.

À la fin de la journée, une équipe C est souvent aussi puissante que son programmeur le plus faible et l’avantage du code obtenu est un multijoueur de 1 ou une pénalité de performance. Ce que je veux dire par là, c’est soit des performances élevées pour un et un seul travail unique dans un environnement unique comportant des décisions de conception uniques, soit il est suffisamment générique pour être utilisé dans plusieurs environnements (autre microcontrôleur, autre stratégie de gestion de la mémoire, autre latence, etc.). compromis de débit, etc., etc.), mais a un coût de performance inhérent.

En C ++, les éléments peuvent être encapsulés par des experts et utilisés dans de nombreux environnements où la génération de code temporel de compilation s’adapte à la tâche spécifique et où la vérification statique empêche les utilisateurs de faire des choses stupides à un coût nul. Ici, nous avons beaucoup moins de compromis entre être générique et être rapide et, par conséquent, du point de vue des coûts et des avantages, nous utilisons le langage le plus performant, le plus sûr et le plus productif.

La critique selon laquelle il existe toujours une grande pénurie de bonnes bibliothèques C ++ incorporées peut conduire à des décisions pragmatiques consistant à utiliser principalement le C sur un compilateur C ++. Les décisions d'utiliser uniquement le C dans un projet sont essentiellement dictées par des considérations idéologiques, par nécessité d'un support hérité ou par l'admission que l'équipe n'est pas assez disciplinée pour s'abstenir d'un ensemble très sélectif de choses stupides que l'on peut faire en C ++ mais pas en C et en même temps assez discipliné pour ne pas faire le plus grand ensemble de bêtises que l'on ne peut pas se protéger en C mais que l'on pourrait en C ++.


Belle addition à ma réponse :) Qui serait ce mystérieux amoureux de C ++? Son profil indique "Apparemment, cet utilisateur préfère garder un air de mystère à son sujet." (bad english, BTW) MAIS AHA le lieu est "Bochum, Allemagne" ..... Rendez-vous à la conférence!
Wouter van Ooijen

Ah ouais j'ai mis à jour mon profil;) c'est bon de savoir que tu viens à emBO ++ ce sera une bonne foule
odinthenerd

10

Mon expérience: formation tout juste sortie de l’école sous l’ancienne programmation de Bell Labs; travaille depuis 3 ans, 2 sur un projet de recherche de premier cycle; acquisition de données / contrôle de processus en VB.NET. A passé un an et demi à travailler sur une application de base de données d'entreprise dans VB6. Travaille actuellement sur un projet pour PC embarqué avec 2 Go de stockage, 512 Mo de RAM, 500 MHz x86; plusieurs applications s'exécutant simultanément écrites en C ++ avec un mécanisme IPC entre les deux. Oui je suis jeune

Mon avis: Je pense que C ++ peut fonctionner efficacement compte tenu de l'environnement que j'ai écrit ci-dessus . Certes, les performances en temps réel difficiles ne sont pas une exigence de l'application utilisée, et dans certaines applications intégrées, cela peut poser problème. Mais voici les choses que j'ai apprises:

  • C ++ est fondamentalement différent de C (c'est-à-dire qu'il n'y a pas de C / C ++). Bien que tout ce qui est valide en C soit valide en C ++, le C ++ est un langage très différent et il est nécessaire d’apprendre à programmer en C ++, pas en C, pour l’utiliser efficacement dans n’importe quelle situation. En C ++, vous devez programmer de manière orientée objet, non pas de manière procédurale, ni un hybride des deux (grandes classes avec beaucoup de fonctions). En général, vous devriez vous concentrer sur la création de petites classes avec peu de fonctions et composer toutes les petites classes en une solution plus grande. Un de mes collègues m'a expliqué que je programmais de manière procédurale dans des objets, ce qui est un véritable gâchis et qui est difficile à maintenir. Lorsque j'ai commencé à appliquer des techniques plus orientées objet, j'ai constaté que la facilité de maintenance / lisibilité de mon code était améliorée.

  • C ++ fournit des fonctionnalités supplémentaires sous la forme d'un développement orienté objet qui peut fournir un moyen de simplifier le code pour en faciliter la lecture / la maintenance . Honnêtement, je ne pense pas qu'il y ait beaucoup d'amélioration de l'efficacité de la performance / de l'espace dans la programmation orientée objet. Mais je pense que la POO est une technique qui peut aider à diviser un problème complexe en plusieurs petits morceaux. Et cela est utile pour les personnes qui travaillent sur le code, un élément de ce processus qui ne devrait pas être ignoré.

  • De nombreux arguments contre C ++ ont principalement à voir avec l'allocation dynamique de mémoire. C a ce même problème aussi. Vous pouvez écrire une application orientée objet sans utiliser de mémoire dynamique, même si l'un des avantages de l'utilisation des objets est que vous pouvez affecter ces éléments de manière dynamique de manière simple. Tout comme en C, vous devez faire attention à la façon de gérer les données pour réduire les fuites de mémoire, mais la technique RAII simplifie cela en C ++ (créer une destruction dynamique de la mémoire en l'encapsulant dans des objets). Dans certaines applications, où chaque emplacement de mémoire compte, cela peut s'avérer trop difficile à gérer.

MODIFIER:

  • WRT la question "Arduino C ++" : Je dirais que C ++ sans gestion de mémoire dynamique peut toujours être utile. Vous pouvez organiser votre code en objets, puis les placer à différents emplacements de votre application, configurer des interfaces de rappel, etc. Maintenant que je développe en C ++, je peux voir de nombreuses façons une application avec toutes les données allouées sur le La pile peut toujours être utile avec des objets. J'avouerai cependant que je n'ai jamais écrit une telle application intégrée pour l'Arduino, je n'ai donc aucune preuve derrière ma réclamation. J'ai quelques opportunités de faire du développement Arduino dans un projet à venir - j'espère pouvoir tester ma revendication là-bas.

2
Je voudrais commenter votre deuxième point. Vous dites que cela aide à diviser un problème complexe en beaucoup de petites choses et que cette fonctionnalité doit être ignorée. C'est la raison exacte pour laquelle je suis si pro-C ++. Un très grand nombre de recherches sur la programmation montre qu'une croissance linéaire de la taille du programme entraîne une croissance exponentielle du temps de développement. Cela va dans le sens opposé: si vous pouvez scinder correctement un programme, vous pouvez donner une décroissance exponentielle au cours du temps de développement. C'est de loin la chose la plus importante.
Kortuk

sur votre deuxième point également: le simple fait d’utiliser une méthodologie de conception POO ne produit pas un code plus compartimenté. Avoir un bon design de base, la façon dont on exprime ce design est laissé au développeur. OOP ne définit pas que vous séparez votre code correctement, il fournit une autre option et plus, l'apparence que vous avez faite, mais, cela n'impose certainement pas une bonne conception, cela revient au développeur.
Mark

C'est toujours vrai. Je n'ai jamais entendu parler d'un langage qui impose un bon design. Je pense que nous pensons surtout que c’est le travail des développeurs et que le C ++ facilite l’utilisation et la mise en oeuvre de manière organisée.
Kortuk

@ Mark - Je suis d'accord. Cela a été un processus d'apprentissage pour moi.
J. Polfer

7

Oui, le problème avec C ++ est l’empreinte accrue du code.

Dans certains systèmes, vous comptez les octets et dans ce cas, vous devrez accepter un coût d’exploitation aussi proche des limites de vos systèmes, ce qui augmente les coûts de développement de C.

Mais, même en C, pour un système bien conçu, vous devez tout garder encapsulé. Les systèmes bien conçus sont difficiles et le C ++ offre aux programmeurs une place pour une méthode de développement très structurée et contrôlée. Il y a un coût à apprendre la programmation orientée objet, et si vous souhaitez y basculer, vous l'acceptez beaucoup. Dans de nombreux cas, la direction préfère continuer avec C et ne pas payer le coût, car il est difficile de mesurer les résultats d'un changement augmente la productivité. Vous pouvez voir un article du gourou des systèmes intégrés, Jack Ganssle, ici .

La gestion dynamique de la mémoire est le diable. Pas vraiment, le diable est auto-routé, la gestion de la mémoire dynamique fonctionne très bien sur un PC, mais vous pouvez vous attendre à redémarrer un PC toutes les deux semaines au moins. Vous constaterez que lorsqu'un système intégré continue de fonctionner pendant 5 ans, la gestion dynamique de la mémoire peut vraiment être gâchée et même commencer à échouer. Ganssle discute de choses comme pile et tas dans son article.

Certaines choses en C ++ sont plus susceptibles de poser des problèmes et utilisent beaucoup de ressources, la suppression de la gestion de la mémoire dynamique et des modèles est une étape importante pour conserver l'empreinte de C ++ plus proche de l'empreinte de C. Cela reste du C ++, vous n'avez pas besoin de dynamique gestion de la mémoire ou des modèles pour écrire un bon C ++. Je n'avais pas réalisé qu'ils supprimaient les exceptions, je considère les exceptions comme une partie importante de mon code que je supprime dans la version, mais que j'utilise jusqu'à ce point. Lors des tests sur le terrain, des exceptions peuvent générer des messages pour m'informer d'une exception interceptée.


1
J’étais d’accord pour dire que l’empreinte de code est un problème, mais récemment, il semble que la taille du flash n’ait que très peu d’influence sur le prix d’un microcontrôleur, beaucoup moins que la taille de la RAM ou le nombre de broches IO.
Wouter van Ooijen

L'argument sur la mémoire dynamique est plus important OMI. J'ai vu des systèmes industriels fonctionner pendant des semaines sans interruption, mais la couche de diagnostic (écrite en C ++) limiterait le temps de redémarrage à environ 12 heures.
Dmitry Grigoryev le

6

Je pensais que ce discours anti-C ++ de Linus Torvalds était intéressant.

L'une des pires caractéristiques du C ++ réside dans le fait que beaucoup de choses dépendent du contexte. Cela signifie simplement que lorsque vous examinez le code, une vue locale donne rarement assez de contexte pour savoir ce qui se passe.

Il ne parle pas du monde des systèmes intégrés, mais du développement du noyau Linux. Pour moi, la pertinence découle de ceci: C ++ nécessite de comprendre un contexte plus large, et je peux apprendre à utiliser un ensemble de modèles d'objet, je ne me fie pas à moi-même de les mémoriser lorsque je dois mettre à jour le code dans quelques mois.

(D'autre part, je travaille actuellement sur un périphérique intégré utilisant Python (et non pas C ++, mais utilisant le même paradigme de programmation orientée objet) qui posera exactement ce problème. Pour ma défense, il s'agit d'un système intégré assez puissant pour être appelé PC. Il ya 10 ans.)


5
Nous pouvons différer, mais je constate que tout en ouvrant un projet, je ne peux pas dire ce qui se passe immédiatement, mais si je sais quelque chose à propos de ce qu'il fait et que j'ai quelque chose de bien codé en C et quelque chose de bien codé en C ++, le C ++ semble toujours plus clair. Vous devez toujours implémenter l’encapsulation pour un bon développement en C, ce qui est très facile à faire avec C ++. Une utilisation correcte des classes peut indiquer très clairement où se trouvent vos interfaces, et elles peuvent être entièrement gérées via un objet.
Kortuk

Totalement d'accord sur l'encapsulation et les classes. La surcharge des opérateurs et l'héritage, pas tellement.
Pingswept

1
Haha, oui, la surcharge de l'opérateur peut être utilisée pour masquer la fonction du code. Si une personne est surchargée par un opérateur, il faut que ce soit pour des raisons claires ou pas du tout. L'héritage ne doit être utilisé que dans des cas spécifiques où vous faites quelque chose qui ressemble au parent avec quelques ajouts. Je pense que je n’utiliserais pas tous les deux la fonction POO. J'ai utilisé les deux, mais dans un système embarqué, je ne peux pas penser à un cas où je le ferais. Tout comme je pense qu'un compilateur avec une limite de 80 caractères sur les noms de variables devrait être immédiatement mis au rebut.
Kortuk

2
Je viens de
vomir

Vous n'êtes pas le seul, mais si cela fonctionne bien et est efficace, je peux pardonner.
Kortuk

6

Je pense que d’autres réponses ont très bien exposé le pour et le contre et les facteurs de décision, alors je voudrais juste résumer et ajouter quelques commentaires.

Pour les petits microcontrôleurs (8 bits), pas question. Vous demandez simplement de vous blesser, il n'y a aucun gain et vous perdrez trop de ressources.

Pour les microcontrôleurs haut de gamme (par exemple 32 bits, 10 ou 100 Mo pour la RAM et le stockage) dotés d’un système d’exploitation correct, c’est tout à fait correct et, j’oserais dire, même ceux qui sont recommandés.

La question est donc: où est la limite?

Je ne sais pas avec certitude, mais une fois que j’ai développé un système pour un uC 16 bits avec 1 Mo de RAM et 1 Mo de stockage en C ++, je le regretterai plus tard. Oui, cela a fonctionné, mais le travail supplémentaire que j'ai fait n'en valait pas la peine. Je devais le mettre en forme, m'assurer que des exceptions telles que des exceptions ne produiraient pas de fuites (le support OS + RTL était plutôt bogué et peu fiable). De plus, une application OO utilise généralement beaucoup de petites allocations, et les frais généraux qui en découlent étaient un autre cauchemar.

Compte tenu de cette expérience, je suppose que pour les projets futurs, je choisirai le C ++ uniquement dans les systèmes d'au moins 16 bits et d'au moins 16 Mo pour la mémoire vive et le stockage. C'est une limite arbitraire, et cela variera probablement en fonction du type d'application, des styles de codage et des idiomes, etc. Cependant, étant donné les mises en garde, je recommanderais une approche similaire.


2
Je ne suis pas du même avis, il n’ya pas de soudain point où le C ++ devient acceptable en raison des ressources système, de bonnes pratiques de conception permettent de conserver l’empreinte C ++ là où se trouve l’empreinte C. Il en résulte un code avec des conceptions POO prenant le même espace. C mal écrit peut être tout aussi mauvais.
Kortuk

1
Cela dépend de la taille de votre application et de l'utilisation que vous faites de certaines fonctionnalités nécessitant plus d'espace (telles que les modèles et les exceptions). Mais personnellement, je préférerais utiliser C plutôt que de me limiter à un C ++ restreint. Mais même dans ce cas, vous aurez les frais généraux d’une RTL plus importante, d’une méthode virtuelle, d’une invocation de chaîne constructeur / destructeur ... ces effets peuvent être atténués avec un codage soigneux, mais vous perdez alors la raison principale de l’utilisation, de l’abstraction et de perspective de haut niveau.
fceconel

4

Certaines fonctionnalités de C ++ sont utiles dans les systèmes intégrés. Il y en a d'autres, comme les exceptions, qui peuvent coûter cher et dont les coûts ne sont pas toujours apparents.

Si j'avais mes compétences, il y aurait un langage populaire qui combine le meilleur des deux mondes et qui inclut certaines caractéristiques qui manquent dans les deux langues; certains fournisseurs incluent quelques-unes de ces fonctionnalités, mais il n'y a pas de normes. Quelques choses que j'aimerais voir:

  1. Les exceptions traitent un peu plus comme Java, où les fonctions qui peuvent lancer ou fuir des exceptions doivent être déclarées comme telles. Bien que l'exigence de telles déclarations puisse être quelque peu gênante du point de vue de la programmation, cela améliorerait la clarté du code dans les cas où une fonction peut renvoyer un entier arbitraire si elle réussit, mais peut également échouer. De nombreuses plates-formes pourraient gérer cela à moindre coût dans le code, par exemple en ayant la valeur de retour dans un registre et une indication de réussite / échec dans l'indicateur de report.
  2. Surcharge des fonctions statiques et en ligne uniquement; D'après ce que j'ai compris, les organismes de normalisation pour le langage C ont évité la surcharge de fonctions afin d'éviter d'avoir à modifier leur nom. Autoriser uniquement les surcharges de fonctions statiques et en ligne éviterait ce problème et donnerait 99,9% des avantages de la surcharge de fonctions externes (les fichiers .h pouvant définir des surcharges en ligne en termes de fonctions externes portant un nom différent).
  3. Surcharges pour des valeurs de paramètre constantes arbitraires ou spécifiques résolvables au moment de la compilation. Certaines fonctions peuvent être intégrées très efficacement lorsqu'elles sont passées avec une valeur constante, mais très faiblement si elles sont passées à une variable. D'autres fois, le code qui peut être une optimisation si une valeur est constante peut être une pessimisation s'il ne l'est pas. Par exemple:
    copie en ligne copy_uint32s (uint32_t * dest, const uint32_t * src, __is_const int n)
    {
      si (n <= 0) retourne;
      sinon si (n == 1) {dest [0] = src [0];}
      sinon si (n == 2) {dest [0] = src [0]; dest [1] = src [1];}
      sinon si (n == 3) {dest [0] = src [0]; dest [1] = src [1]; dest [2] = src [2];}
      sinon si (n == 4) {dest [0] = src [0]; dest [1] = src [1]; dest [2] = src [2]; dest [3] = src [3];}
      else memcpy ((void *) dest, (const void *) src, n * sizeof (* src));
    }
    
    Si 'n' peut être évalué au moment de la compilation, le code ci-dessus sera plus efficace qu'un appel à memcpy, mais si 'n' ne peut pas être évalué à la compilation, le code généré sera beaucoup plus gros et plus lent que le code qui simplement appelé Memcpy.

Je sais que le père du C ++ n’apprécie pas trop une version du C ++ incorporée, mais je pense qu’elle pourrait offrir des améliorations considérables par rapport à l’utilisation de C.

Quelqu'un sait si quelque chose comme ce qui précède est envisagé pour tout type de norme?



@Joby Taffey: Je suppose que j'ai édité mon post pour ne pas mentionner que le créateur de C ++ n'était pas enthousiaste pour un sous-ensemble incorporé; Je suis conscient qu'il y a eu des efforts, mais d'après ce que j'ai compris, ils n'étaient pas vraiment allés aussi loin. Je pense qu'il serait certainement utile d'utiliser un langage normalisé qui conviendrait aux processeurs 8 bits, et des fonctionnalités telles que celles que j'ai décrites ci-dessus sembleraient utiles sur n'importe quelle plate-forme. Avez-vous entendu parler de langues offrant des choses comme le n ° 3 ci-dessus? Cela semblerait très utile, mais je n’ai jamais vu aucun langage l’offrir.
Supercat

"Le père de C ++" n'a aucune expérience de la programmation de systèmes intégrés, alors pourquoi se soucierait-il de son opinion?
Lundin

@Lundin: Le fait que certaines personnes influentes semblent se soucier de ses opinions sur diverses questions semble être une raison, en soi, pour que d'autres personnes le fassent. Je pense que depuis que j'ai écrit ce qui précède, la puissance croissante des modèles peut offrir de nouvelles possibilités d'avoir des surcharges basées sur les constantes pouvant être résolues au moment de la compilation, bien que ce soit beaucoup moins proprement que si une telle chose était supportée comme une compilation. fonctionnalité de temps (d'après ce que j'ai compris, on spécifierait un modèle qui devrait essayer différentes choses dans l'ordre et aller avec le premier qui n'échoue pas ...
supercat

... mais cela demanderait au compilateur de perdre un peu d’effort à compiler des substitutions potentielles qui seraient ensuite rejetées. Etre capable de dire plus proprement "Si c'est une constante, faites-le; sinon, faites-le" sans "faux départ", cela semblerait être une approche plus propre.
Supercat

3

C ++ est plus qu'un langage de programmation:

a) C'est un "meilleur" C b) C'est un langage orienté objet c) C'est un langage qui nous permet d'écrire des programmes génériques

Bien que toutes ces fonctionnalités puissent être utilisées séparément, les meilleurs résultats sont obtenus lorsque les trois d'entre elles sont utilisées simultanément. Néanmoins, si vous choisissez de n'en choisir qu'un, la qualité du logiciel embarqué augmentera.

a) C'est un "meilleur" C

C ++ est un langage typé fort; plus fort que C. Vos programmes bénéficieront de cette fonctionnalité.

Certaines personnes ont peur des pointeurs. C ++ inclut les références. Fonctions surchargées.

Et cela vaut la peine de dire: Aucune de ces fonctionnalités n’est générée par des programmes plus importants ou plus lents.

b) C'est un langage orienté objet

Quelqu'un a dit dans cet article qu'abstraction de la machine dans les microcontrôleurs n'est pas une bonne idée. Faux! Nous tous, ingénieurs intégrés, avons toujours fait abstraction de la machine, à l’aide d’une autre méthode que celle du C ++. Le problème que je vois avec cet argument est que certains programmeurs ne sont pas habitués à penser aux objets, c'est pourquoi ils ne voient pas les avantages de la POO.

Lorsque vous êtes prêt à utiliser le périphérique d'un microcontrôleur, il est probable que le périphérique a été extrait pour nous (de vous-même ou d'un tiers) sous la forme du pilote de périphérique. Comme je l'ai dit précédemment, ce pilote utilise le code C, comme le montre l'exemple suivant (tiré directement d'un exemple de NXP LPC1114):

/ * Configuration de la minuterie pour le match et l’interruption à TICKRATE_HZ * /

Chip_TIMER_Reset (LPC_TIMER32_0);

Chip_TIMER_MatchEnableInt (LPC_TIMER32_0, 1);

Chip_TIMER_SetMatch (LPC_TIMER32_0, 1, (timerFreq / TICKRATE_HZ2));

Chip_TIMER_ResetOnMatchEnable (LPC_TIMER32_0, 1);

Chip_TIMER_Enable (LPC_TIMER32_0);

Voyez-vous l'abstraction? Ainsi, lors de l'utilisation de C ++ dans le même but, l'abstraction passe au niveau supérieur grâce au mécanisme d'abstraction et d'encapsulation du C ++, à un coût nul!

c) C'est un langage qui nous permet d'écrire des programmes génériques

Les programmes génériques sont réalisés au moyen de modèles, et les modèles ne génèrent également aucun coût pour nos programmes.

De plus, le polymorphisme statique est obtenu avec des modèles.

Méthodes virtuelles, RTTI et exceptions.

Il existe un compromis lors de l'utilisation de méthodes virtuelles: un meilleur logiciel contre une pénalité de performances. Cependant, rappelez-vous qu'une liaison dynamique est susceptible d'être implémentée à l'aide d'une table virtuelle (un tableau de pointeurs de fonction). J'ai souvent fait la même chose en C (même régulièrement), aussi je ne vois pas les inconvénients liés à l'utilisation de méthodes virtuelles. De plus, les méthodes virtuelles en C ++ sont plus élégantes.

Enfin, un conseil sur RTTI et les exceptions: NE LES UTILISEZ PAS dans les systèmes embarqués. Evitez-les à tout prix !!


2

Mon fond, intégré (mcu, pc, unix, autre), en temps réel. Critique de sécurité. J'ai présenté un ancien employeur à STL. Je ne fais plus ça.

Du contenu de flamme

C ++ est-il adapté aux systèmes embarqués?

Meh C ++ est une douleur à écrire et à maintenir. C + est un peu correct (n'utilisez pas certaines fonctionnalités)

C ++ dans les microcontrôleurs? RTOS? Grille-pain? PC intégrés?

Encore une fois je dis Meh. C + n'est pas si mal, mais l'ADA est moins douloureuse (et c'est vraiment dire quelque chose). Si vous êtes chanceux comme moi, vous devez faire de la Java intégrée. Un accès contrôlé à la matrice et l'absence d'arithmétique de pointeur permettent d'obtenir un code très fiable. Les garbage collectors dans Java intégré ne sont pas prioritaires, et la mémoire et la réutilisation des objets sont étendues. Un code bien conçu peut donc être exécuté à tout jamais sans GC.

La POO est-elle utile sur les microcontrôleurs?

Bien sûr est. L'UART est un objet ..... Le DMAC est un objet ...

Les machines à états d'objet sont très faciles.

C ++ supprime-t-il trop le programmeur du matériel pour être efficace?

Sauf s’il s’agit d’un PDP-11, C n’est pas votre processeur. C ++ étant à l’origine un pré-processeur sur C, Bjarne Stroustrup ne se moquerait plus d’avoir simulé des simulations lentes alors qu’il était chez AT & T. C ++ n'est pas votre processeur.

Allez chercher un MCU qui exécute des bytecodes java. Programme en Java. Rire les gars C.

Le C ++ d’Arduino (sans gestion de mémoire dynamique, modèles, exceptions) doit-il être considéré comme du "vrai C ++"?

Nan. tout comme tous les compilateurs C bâtardés pour MCU.

À l’avenir, Java intégré ou ADA intégré sont normalisés (ish); tout le reste est chagrin.


2
Est-il si facile de trouver des microcontrôleurs prenant en charge Java? Je pense que cela limiterait considérablement les choix. Et quelles sont vos expériences en matière de pénalité de performance (puisque dans les États-Unis, vous n’auriez généralement pas d’AEC)? Qu'en est-il de l'imprévisibilité du GC dans les systèmes temps réel?
fceconel

2
Quels sont les MCU disponibles qui prennent en charge Java intégré?
J. Polfer

www.ajile.com pour commencer.
Tim Williscroft le

+1 pour Ada. Il y a beaucoup de choses à faire en embarqué, y compris Arduinos.
Brian Drummond

machine virtuelle Java portable pour les micros écrits en c est open source. dmitry.co/index.php?p=./04.Thoughts/…
Tim Williscroft

-2

Les systèmes intégrés sont conçus pour effectuer certaines tâches spécifiques, plutôt que d'être un ordinateur à usage général pour plusieurs tâches. Un système intégré est une combinaison de matériel informatique et de logiciels. C est la mère de toutes les langues modernes. C'est un langage bas, mais puissant, qui parle tout et qui traite de tout type de matériel. C / C ++ est donc un choix optimal pour développer un logiciel pour système embarqué, ce qui est très complet pour chaque système embarqué. Comme nous le savons, C est un langage en développement. Le système d'exploitation UNIX est écrit en C. Parce que le développement de logiciels réussit souvent à sélectionner le meilleur langage pour un projet donné, il est surprenant de constater que le langage C / C ++ s'est avéré approprié pour les processeurs 8 bits et 64 bits. ; dans les systèmes avec octets, kilooctets et mégaoctets de mémoire. C a l'avantage de l'indépendance du processeur, ce qui permet aux programmeurs de se concentrer sur des algorithmes et des applications, plutôt que sur les détails d'une architecture de processeur particulière. Cependant, nombre de ces avantages s'appliquent également aux autres langages de haut niveau. Mais C / C ++ a réussi là où tant d’autres langages ont largement échoué?


6
Je ne suis vraiment pas sûr de ce que cela ajoute à la discussion.
Dave Tweed

-3

<rant>

Je pense que C ++ est un langage de merde en premier lieu. Si vous souhaitez utiliser la POO, écrivez des programmes Java. C ++ ne fait rien pour appliquer les paradigmes de programmation orientée objet, car l'accès direct à la mémoire est tout à fait en votre pouvoir.

Si vous avez un MCU, vous parlez probablement de moins de 100 Ko de mémoire flash. Vous voulez programmer dans un langage dont l'abstraction de la mémoire est: lorsque je déclare une variable ou un tableau, il obtient de la mémoire, un point; malloc (alias "nouveau" mot clé en C ++) devrait être plus ou moins banni des logiciels embarqués, sauf peut-être dans de rares occasions, un appel lors du démarrage du programme.

Bon sang, il y a (fréquemment) des temps dans la programmation intégrée où le C n'est pas assez bas, et vous devez faire des choses comme allouer des variables aux registres et écrire un assemblage en ligne pour renforcer vos routines de service d'interruption (ISR). Des mots-clés tels que "volatile" deviennent diablement importants à comprendre. Vous passez beaucoup de temps à manipuler la mémoire au niveau du bit , pas au niveau de l' objet .

Pourquoi voudriez-vous vous leurrer en pensant que les choses sont plus simples qu'elles ne le sont réellement?

</ rant>


Mon problème ici est simplement: pourquoi je veux connaître la complexité du pilote écrit pour contrôler USART1 s'il a été entièrement développé pour gérer l'interface.
Kortuk

1
Je ne vous ai pas voté négativement, mais je voudrais souligner que le C ++ n’a pas besoin de faire respecter la POO, mais donne simplement les outils pour le faire. L'application de normes de codage de qualité est le travail du développeur. Cela peut aider si la langue facilite les choses, mais la langue ne le fera jamais seule. C peut être illisible dans certains cas.
Kortuk

1
Toutes les langues sont bonnes pour quelque chose. C ++ est rapide. La POO, si elle est bien exécutée, facilite beaucoup le travail en parallèle de plusieurs développeurs et leur permet de coder pour l'inconnu. Je pense que c’est la raison pour laquelle il a tant de poids dans le développement de jeux.
Toby Jaffey

1
Oui je suis d'accord. La raison pour laquelle je le vois pour le monde intégré est due à la quantité de fonctionnalités et de fonctions ajoutées à beaucoup des différents systèmes déjà en place et aux nouveaux systèmes en cours de développement. Le projet devient de plus en plus grand. Soit nous prenons plus de temps pour les développer, soit nous commençons à appliquer et à contourner ce que le monde CS a déjà fait sur les PC.
Kortuk

5
Encore une autre personne qui ne comprend pas bien le C ++. Cela me surprend toujours combien il y en a.
Rocketmagnet
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.