Hallo Gemeinde,
der Betreff sagt eigentlich schon alles. Ich programmiere ATMEGAS in C.
Und ausschließlich in C. Assembler ist nicht so meine Welt. Aber, macht
es Sinn, sich in C++ einzuarbeiten, wenn man nur µCs programmieren will?
Man hört ja oft davon, dass C++ Programme sehr groß sind. Ich habe zu
Testzwecken mal das Minimalprogramm geschrieben:
1
#include<iom128.h>
2
#include<iostream.h>
3
#include<stdio.h>
4
intmain()
5
{
6
intsumme,a,b;
7
cout<<"a und b eingeben:";
8
cin>>a>>b;
9
summe=a+b;
10
cout<<"summe"<<summe;
11
}
Das Ergebnis:
über 11000 Byte Code, 438 Byte Data.
Sieht ja nicht so prickelnd aus.
MW
Zum einen muss man sich fragen, ob man ueberhaupt mit dynamischen
Datenstrukturen arbeiten will. Als naechstes : braucht man
Stringbearbeitung ? Wenn ja, in welchem Masse ?
Das war ein Beispiel aus dem Buch. Ich verstehe, da geht es mir genauso,
wie vielen Bascommern, man weis nicht (zumindest am Anfang), was sich
hinter einigen Befehlen verbirgt.
MW
Hallo,
ich würde nicht sagen, dass C++ grundsätzlich immer Platzverschwendung
bedeutet, es kann auch einfach nur zu lesbarerem Quelltext führen.
Beispiel in C:
funktionsaufruf (&objekt, parameter1, parameter2);
C++:
objekt->funktionsaufruf (parameter1, parameter2);
Intern dürfte hier in etwa das gleiche passieren, nur dass die Funktion
selbst in C++ einfacher lesbar ist, denn der Zeiger auf das Objekt steht
nicht bei jeder Membervariable davor.
Etwas Anderes ist natürlich die Nutzung von Bibliotheksfunktionen, die
oft viel mehr können als gerade gebraucht wird und daher den Code
aufblähen. Das wird dann aber auch bei Standard-C-Funktionen (z.B.
printf) so sein.
Gruß,
Martin
Michael Wilhelm wrote:
> Hallo Gemeinde,>> der Betreff sagt eigentlich schon alles. Ich programmiere ATMEGAS in C.> Und ausschließlich in C. Assembler ist nicht so meine Welt. Aber, macht> es Sinn, sich in C++ einzuarbeiten, wenn man nur µCs programmieren will?>> Man hört ja oft davon, dass C++ Programme sehr groß sind. Ich habe zu> Testzwecken mal das Minimalprogramm geschrieben:
Das Problem an deinem Minimalprogramm ist, dass es eben
nicht minimal ist. Die Stream Library schlägt schon ganz
ordentlich zu Buche. Das ist im Grunde ähnlich dem C
Problem beim gcc, wenn du printf benutzt. Ein printf und
dazu noch die Floating Point Library und dein Programm
legt ordentlich in der Größe zu.
Im Regelfall sind aber C++ Programme auch nicht wesentlich
größer als C Programme, wenn wir mal vom notorischen Fall
der Stream Libraries absehen.
Dafür hast du aber bei der Programmierung einige Freiheitsgrade
und vor allen Dinge einiges an Sicherheit mehr. Durch die
Verwendung von OOP Prinzipien kann man sich das Leben dann
doch in einigen Bereichen einfacher machen.
Die Kernfrage ist allerdings: Bringt mir das auf einem 'kleinen'
µC mit eher kleinen Programmen was. Wenn dein Programm sowieso
nur aus 30 oder 40 Zeilen C Code besteht, dann wird der entsprechende
C++ (im Source Code) wahrscheinlich auch nicht kürzer ausfallen.
Compiliert werden sich die Programme in der Größe auch kaum
unterscheiden.
Auf der anderen Seite hat es natürlich dann schon etwas
für sich, wenn ich eine Klasse für einen Timer habe, und anstelle
von 'kryptischen' Bitgepfiemel in den Control Registern kann ich
ganz einfach Memberfunktionen aufrufen dieser Klasse aufrufen.
>Auf der anderen Seite hat es natürlich dann schon etwas>für sich, wenn ich eine Klasse für einen Timer habe, und anstelle>von 'kryptischen' Bitgepfiemel in den Control Registern kann ich>ganz einfach Memberfunktionen aufrufen dieser Klasse aufrufen.
Das ist dann quasi ein Treiber. Da tritt die Frage auf, nach welchen
Gesichtspunkten wurde dieser Treiber entworfen. Wenn die souce nicht
beiliegt, kann man das dann nicht nachschauen, und dann ist sowas
fuer mich wertlos.
ist die <iostream.h> beim WinAVR nicht dabei oder ist mein gcc V4.1.1
schon wieder zu alt?
mag das AVRStudio überhaupt cpp files? Als Endung für Sourcefiles werden
nur .c und .s erlaubt.
6635 wrote:
>>Auf der anderen Seite hat es natürlich dann schon etwas>>für sich, wenn ich eine Klasse für einen Timer habe, und anstelle>>von 'kryptischen' Bitgepfiemel in den Control Registern kann ich>>ganz einfach Memberfunktionen aufrufen dieser Klasse aufrufen.>> Das ist dann quasi ein Treiber. Da tritt die Frage auf, nach welchen> Gesichtspunkten wurde dieser Treiber entworfen. Wenn die souce nicht> beiliegt, kann man das dann nicht nachschauen, und dann ist sowas> fuer mich wertlos.
Das Problem hast du aber immer. Das ist ja nicht C++ spezifisch.
Also ich habe noch kein Programm gesehen, das in C++ kleiner wäre als in
C++ (ich meine natürlich den endgültigen asm-Code). Umgekehrt aber
schon.
Ob C++ lesbarer ist oder nicht, ist wohl Geschmackssache.
Aber C++ verführt natürlich dazu, bereits bestehende "Libs" zu
verwenden. Ist ja auchd er Sinn von C++. Nur weiß man oft nicht, wer was
wie programmiert hat und kann bei Fermd-Libs gewaltig auf die Nase
fallen.
Deshalb bevorzuge ich, wenns zeitlich vertretbar ist, das alte C ohne
++.
Frank wrote:
> Also ich habe noch kein Programm gesehen, das in C++ kleiner wäre als in> C++ (ich meine natürlich den endgültigen asm-Code). Umgekehrt aber> schon.
Das kann gut sein, da C++ viel mehr Features unterstützt, die natürlich
mehr Overhead brauchen (Runtime Type Information bspw.). Aber man muss
diese ja nicht nutzen! (Und das ist der Knackpunkt)
> Ob C++ lesbarer ist oder nicht, ist wohl Geschmackssache.
Stimmt, aber ich würde mal vermuten dass einigen Leuten eine
objektorientierte Struktur beim Entwickeln hilft, als schädigt.
> Aber C++ verführt natürlich dazu, bereits bestehende "Libs" zu> verwenden. Ist ja auchd er Sinn von C++. Nur weiß man oft nicht, wer was> wie programmiert hat und kann bei Fermd-Libs gewaltig auf die Nase> fallen.
Sorry, aber da sehe ich (noch) keinen Sinn drin. Warum verführt C++
dazu, aber C nicht? Und ich glaube, dass Standardbibliotheken (Sprich:
Die, die beim Compiler mitgeliefert werden) wohl (in der Regel) die am
besten gewarteten sind.
> Deshalb bevorzuge ich, wenns zeitlich vertretbar ist, das alte C ohne> ++.
Glücklicherweise ist C++ ja abwärtskompatibel.
Übrigens: Ich halte das erneute Aufwärmen der Diskussion für
unangebracht. Wenn ich mich richtig erinnere, sollte es über dieses
Thema bereits mehrere längere Threads drüber geben.
PS: Für die AVR32 liefert Atmel eine fertige C++ Umgebung aus.
C++ macht aber einiges Modularer. Z.B. Sind viele LCD-Libs statisch für
ein Display ausgelegt, sowas auf mehrere zu erweitern ist dann
Pfriemelei. In C++ baut man sowas gleich so das man mehrere Instanzen
von Displays (oder sonstiger Hardware) anlegen kann.
Nachteilig sehe ich das dann viel mit Pointern gearbeitet wird und haben
ja gerade die AVRs nicht ihre Stärken, d.h. es dürfte viel Overhead
durch die indirekten Methodencalls hinzukommen. Aber man muß ja nicht
immer alles dem Performance Gott opfern.
Hi,
also bei C kann man auch, wenn man sich etwas dran hält
Displayansteuerungen recht universell schreiben. Man macht eine
display.h (oder wie auch immer man die nennt) und erstellt dort alle
Prototypen (disp_init(), write_char(), line(),...) und man bindet dann
aber zum compilieren/linken die entsprechend verwendete C-Datei ein, die
gerade zu dem Display passt. Diese muss natürlich alle
Prototypfunktionen aus der display.h auch implementieren.
Was mich an dem ersten Beispiel in diesem Thread interessiert: Ist das
jetzt ein gutes Beispiel für C++? Wird da schon was objektorientiert
gemacht? Gibt es vielleicht kleine Beispiele, wo die Anwendung von
Objektorientierung wirklich Sinn macht in Bezug auf Lesbarkeit?
Gruß
Steffen.
ja, das geht auch, aber die Betonung sollte auf ein vs. mehrere
Resourcen (Displays, Sensoren, SD-Cards etc.) liegen. In C ist ein
Ansatz mit Handles zu arbeiten. Da werden dann statische Arrrays mit
fester Anzahl für die Parameter gespeichert.
Beispiel:
1
HANDLEdisp1=init_display(PORTA,...);
2
HANDLEdisp2=init_display(PORTB,...);
3
4
write_char(disp1,"hello");
in init_display muss dann die Handleverwaltung gemacht werden. In C++
finde ich sowas eleganter:
1
CDisplaydisp1(PORTA,...);
2
CDisplaydisp2(PORTB,...);
3
4
disp1.write_char("hello");
Sieht erstmal nicht grossartig anders aus, aber ich kann (fast) beliebig
viele Instanzen anlegen ohne in init_display() Arrays für eine max.
Anzahl Displays vordefinieren zu müssen. Ist natürlich alles auch
Geschmacksache.
@Simon: die anderen Diskussionen hier waren auch interessant, eine
längere da ist aber nach float vs. int abgedriftet.
Und wie ich es jetzt verstanden habe gibt es keine iostream.h für gcc,
das original Posting ist wohl mit IAR oder anderem erstellt worden.
Hätte da auch gleich erwähnt werden können.
Ohne jetzt zur Aufwärmung bzw. zum Anheizen des Threads beitragen zu
wollen, einfach mal ein kurzer Schwank aus der Praxis:
Beim Design einiger neuer Boards in der zweiten Hälfte des letzten
Jahres habe ich - wie schon seit einiger Zeit praktiziert - wieder einen
kleinen AVR (meist Mega8) "in die Ecke gepackt" um damit immer wieder
gerne benutze Initialisierungs- und Überwachungsfuktionen (Spannungs- /
Temperaturüberwachung, Reset/Hochfahren einzelner Bausteine oder
Funtionsgruppen etc.) flexibel zu realisieren. Meist bin ich dann bei
der Erstinbetriebnahme der Platinen der Erstellung der ("offiziellen")
Firmware weit voraus und "bastle" mir daher mit Hilfe gängiger Libs
(clib, Procyon, Fleury) schnell mal eine Rumpf/Debug-Firmware zusammen
um überhaupt weiterzukommen. Die resultierende Software füllt incl.
eines kleinen Kommandozeilen-Interpreters und einiger weiterer für's
Debugging der Hardware gebrauchten Funktionen den Mega8 dann meistens so
zu 50-80% (die "finale" Firmware lag dann meist 5-10% darüber).
Leider fiel in den selben Zeitraum die Umstelllung der
Firmware-Schreiberei von C nach C++ und als die Kollegen dann (mal
wieder "just in time" ;-) ) die Firmware für die Boards schrieben,
passte eine Spannungsüberwachung, eine Temperaturüberwachung, ein
"Hochfahrsequenzer" und ein paar Debug-Ausgaben via U(S)ART zusammen
schon nicht mehr in den Mega8. Natürlich war es nicht möglich, mal eben
schnell für diese Projekte wieder auf C zurückzugehen, so wurden die
schon gefertigten Geräte nochmal zerlegt und die Mega8-er durch
Mega168-er ersetzt.
Dafür ist das Ganze nun natürlich viel leichter wartbar. :-/
Es lebe der Fortschritt!
In Zukunft werde ich also den Mega84 als "Default-Prozessor" verwenden
und überall wo der bisher schon drauf war, auf den STR912 (mit all
seinen Freuden gegenüber den AVRs, wie z.B. erheblich geringere
Treiberleistung der Ports, vergleichsweise lahme IRQ-Bearbeitung,
zusätzliche Core-Versorgung, etc.) umsteigen. Bei ARM und 256K Flash
aufwärts klappt's dann auch wieder mit den Debug-Ausgaben am UART :-))
(oder eher :-(( ?).
ich habe früher viel an Projekten mitprogrammiert (in C) die
kundenspezifisch waren und es waren immer ähnliche Anlagen (Messgeräte)
die von vorhergehenden kopiert wurden. Das funktionierte überhaupt nur
durch starke Standardisierung von Namen, Libs usw. Dabei fing man sich
aber immer wieder Fehler ein durch Konstanten die nicht angepasst
wurden, nicht initialisierten Zeigern oder sonstigen C-Fallen. Bei
kleinen überschaubaren Projekten funktioniert das, aber die Dinger
wurden immer komplexer und dementsprechend stieg die Fehlerhäufigkeit.
Ich bin daher eher zum C++ Fan geworden :-) Wenn es um Serienproduktion
und optimale Optimierung geht ist jeder cent gesparte Hardware natürlich
n*Geräte wert. Bei kundenspezifischen Projektarbeiten halte ich aber die
Wartbarkeit für wesentlich wichtiger, vor allem weil an unseren Geräten
auch nach 20 Jahren noch Programmänderungen vorgenommen werden! Das
machen allerdings nur noch wenige Spezies die die alte SW mittlerweile
in- und auswendig kennen. Heute wird das Ganze grafisch durch
Kistenschieben programmiert, C++ kommt da intern für die
Funktionsbausteine zum Einsatz aber nicht für die
Anwendungsprogrammierung. Hardware sind allerdings auch PCs.
Ich habe mein Beispiel mal in das AVRStudio gehackt... aber der
Assemblercode der da rauskommt sieht ziemlich unleserlich aus. Es geht,
man müsste es mal gegen eine grössere auskodierte Lib stellen.
Also macht es vor allem Sinn, auf C++ zu setzen, wenn sich im Code viele
Doppelungen auftuen. Mehrere Serielle Schnittstellen, Software- Regler
o. ä. Aber gerade bei Displays wird es auf nem AVR wohl wenig Sinn
machen ;-) wenn überhaupt ist dann bei den meisten nur ein Display
angeschlossen ;-)
Steffen.
Ich verstehe nicht so ganz, warum diese Meinung hier immer noch
rumgeistert. Auch in C kann man doch problemlos mehrere Instanzen einer
Datenstruktur anlegen und unabhängig benutzen.
Definition der DS:
typedef struct Name {...}
Definition der Operationen:
void initName (Name *instance, <args>);
<rt> benutzeName (Name *instance, <args);
...
Anlegen der Instanzen:
Name instance1;
Name instance2;
...
Was man halt nicht bekommt sind die OO-Nettigkeiten wie Vererbung, aber
das macht erst in größeren Projekten Probleme (die dann eh nicht in den
µC passen).
Mir wäre ein sauber geschriebenes C von einem Profi
der Wert auf Sauberkeit seines Codes legt lieber als
ein C++ vom jemand der die Sprache unsicher beherrscht.
Ich selber schreibe in beiden gern.
Auf PC Seite eher C++, auf uC Seite eher C.
Die Libraries machen wohl den Haupunterschied und
dynamische Speicherverwaltung würde ich händisch machen.
grüsse, Daniel
@Morin: Klar kann man in C alles machen. Aber C unterstützt eben keine
typischen C++ Strukturen. Muss es selber machen und damit passt es nicht
automatisch zu dem output anderer Progger. (Mus jeder selber wissen, wie
stark diese Nachteil ist).
Moin Jungs (und Mädels),
danke für die Statements.
@ Johannes
>Und wie ich es jetzt verstanden habe gibt es keine iostream.h für gcc,>das original Posting ist wohl mit IAR oder anderem erstellt worden.>Hätte da auch gleich erwähnt werden können.
Mir ging es nicht um eine spezifische IDE. Du hast recht, es ist IAR.
Aber das war nicht die Frage.
Nun muss ich die Antworten bewerten. Es war ja alles dabei von "Hände
weg mit C++ bei µC" bis "besser wartbar, besser zu lesen, schneller in
der Entwicklung...".
MW
Was gerne vergessen wird, ist, daß man, wenn man C++ nimmt, deshalb
nicht unbedingt gleich sämtliche Features der Sprache einsetzen muß. C++
ist größtenteils kompatibel zu C, d.h. man kann im Prinzip den C-Code
mit wenigen Änderungen als C++ übersetzen, und das Ergebnis ist auch
größtenteils gleich. Die Sprache selbst bietet aber viele zusätzliche
Features. Man hat also von C++ erstmal keinen Nachteil, sondern nur den
Vorteil, mehr Sprachfeatures nutzen zu können.
Man kann sich z.B. ein Festkomma-Klassentemplate mit überladenen
Operatoren basteln, mit dem man Festkomma-Typen mit wählbarer Vor- und
Nachkomma-Stellenzahl bekommt, die man fast genauso einsetzen kann, wie
eingebaute Typen. Das geht in C eben nicht so elegant. Da muß man sich
dann mit wilden Makro-Konstrukten behelfen, die dann übel aussehen und
weniger flexibel, dafür aber auch nicht effizienter sind.
So, habe eben einen funktionierenden C-Code nach C++ portiert und
compiliert und gelinkt. Erstaunlich
C-Code 1938 Byte Code - 209 Byte Data
C++ 2192 Byte Code - 145 Byte Data
Also ist C++ nicht unbedingt aufgeblähter. Nette Erkenntnis vor allem im
RAM-Bereich. Das heißt, Erkenntnis eigentlich nicht, da ich nicht weis,
wo gespart und nicht gespart wird.
MW
@Michael
Kannst/darft/willst du den Code mal zeigen? Mich interessieren solche
Vergleiche auch. Man kann ja aus den Erfahrungen anderer lernen ;-)
Steffen.
> Leicht möglich, dass C++ aufgrund diesbezüglich etwas anderer> Vorschriften diverse "const" Daten zu Code zählt, C hingegen zu> Daten.
In C++ gibt es im Gegensatz zu C echte Konstanten. In C umgeht man diese
Einschränkung ja in der Regel, indem man stattdessen ein Makro
verwendet.
@High-Performer:
> @Morin: Klar kann man in C alles machen. Aber C unterstützt eben keine> typischen C++ Strukturen. Muss es selber machen und damit passt es nicht> automatisch zu dem output anderer Progger. (Mus jeder selber wissen, wie> stark diese Nachteil ist).
Wollts nur mal gesagt haben, da das bei meinen Vorpostern etwas anders
rüberkam ;)
Das mit dem "Output anderer Progger" ist richtig, aber inwiefern bei
einem µC mit wenigen K Programmspeicher mehrere Progger beteiligt sind
ist fraglich... für größere Dinger geb ich dir auf jeden Fall Recht.
@Michael:
> C-Code 1938 Byte Code - 209 Byte Data> C++ 2192 Byte Code - 145 Byte Data
Mein Tip: Versuch rauszufinden, wo der Unterschied liegt (z.B. Ausgabe
als Assembler-Code statt Maschinencode). Dann kriegst du am ehesten raus
ob C++ für dich in Frage kommt und was du evtl. dafür machen musst.
@Rolf:
> Man kann sich z.B. ein Festkomma-Klassentemplate mit überladenen> Operatoren basteln
Stimmt, das hatte ich vergessen. Überladene Operatoren sind eines der
C++ Features die am ehesten in Frage kommen, einfach weil es nur um die
Schreibweise geht und zur Laufzeit nix davon übrig bleibt.
Weniger in Frage kommen z.B. RTTI und Exceptions, in der Mitte steht
Methoden-Überschreiben.
Wird wohl schon ein AVR-Programm sein, aber wahrscheinlich keins für
WinAVR. Aber wer <iostream> auf Microcontrollern verwendet und sich über
reichlich Wasserkopf beklagt, ist selber schuld.
Und wenn du das nicht verstehst, dann vielleicht weil das C++ ist und
nicht C.
Ich wüßte von keinem Compiler für AVR, der eine <iostream> anbietet.
Welcher ist da verwendet worden?
> Aber wer <iostream> auf Microcontrollern verwendet und sich über> reichlich Wasserkopf beklagt, ist selber schuld.
Ein hinter den Kulissen (streambufs und locales) reduziertes cout/cin
könnte deutlich sparsamer sein als printf. Da bräuchte man auch nicht
wie beim printf der avr-libc verschiedenen Varianten, um bei
Nichbenutzung von floating point nicht so großen Code zu haben.