Hallo!
Ich habe vor 2 Jahren mit den AVRs angefangen. Da ich eigentlich C++
Programmiererin bin, wollte ich meine schicke dynamische Menu-Klasse
verwenden, wurde aber von dem C++-Support von avr-g++ derbst enttäuscht:
keine new, kein delete. (Von exceptions will ich gar nicht erst
sprechen). Also habe ich erstmal alles umständlich in C umgeschrieben.
Ca. 1 Jahr später bin ich dann auf MSP430 umgestiegen, weil mit diese
saubere von Neumann Architektur sehr gefiel. Aber der C++-Support von
msp430-g++ war auch nicht besser. Demnächst plane ich auf ARM
umzusteigen. Wie sieht's da aus? Kann arm-g++ z.B. sowas compilieren:
"Da ich eigentlich Formel-1-Pilotin bin, habe ich neulich mal
versucht, das Rennrad bis zum Anschlag zu bringen. Ich bin derb
enttäuscht worden. Immer, wenn ich eine richtig freie Strecke
vor mir hatte, trottelte das Fahrzeug so allmählich vor sich
hin. Jetzt möchte ich mir ein Mofa zulegen. Funktioniert dort
eigentlich der Nachbrenner richtig?"
Wieso "Anwandlungen"?
C++ auf dem AVR mit der GCC wird schon in der FAQ der Doku zur avr-libc
behandelt. Es fehlt einfach die STL.
Auf dem ARM sieht das - WIMRE - besser aus. Aber wenn man's nicht weiss:
einfach ausprobieren.
Btw.: einen Wrapper um new und delete wird unsere C++-F1-Pilotin wohl
doch noch hinbekommen!?
mal abgesehen davon, was der AVR-GCC jetzt für die C++-Welt unterstützt
oder nicht bzw. ob es die STL gibt oder nicht - man kann mit C++ auch
ganz wunderbar Programme schreiben, ohne gleich eine dynamische
Speicherverwaltung, Exceptions oder RTTI zu verwenden. Diese Konzepte
sind für komplexe Softwarearchitekturen vielleicht wirklich hilfreich,
aber auf einem AVR zum Teil einfach vollkommen deplatziert, weil sie
halt auch einen Batzen Ressource kosten. Wozu braucht man in obigem
Beispiel eigentlich ein new()? Die Variable kommt auf den Stack -
fertig, dann spart man sich auch gleich noch ein paar Speicherlöcher!
Ciao, Fabian
Ähem,
also echtes C++ mit Objektorientierung und dem ganzen schönen
Exceptiongedöhns usw. gibt es nicht beim AVR-GCC !
Also alles schön in C proggen und gut ist ;-)
Es geht ein subset des C++-Standards.
Was es nicht geht:
- Exceptions (und das ist nach meinem Empfinden auch nicht nötig,
vielleicht erklärt mir mal jemand wozu man bei einer embedded
Applikation exceptions benötigt)
- new/delete Das kann man sich über wrapper so man nicht ohne auskommt,
selbst schreiben. Oder man nutzt malloc/free und Konstruktionsmethoden.
- Standard-Bibliothek (und damit keine IO-streams, sowie STL). Aber: Man
kann bei Bedarf einen STL-Port integrieren.
s. auch die FAQ zur libc
An einer Stelle möchte ich Jörg widersprechen (und im selben Atemzug für
die libc loben): C++ hat nichts mit Formel 1 zu tun und mit der
aktuellen Version des avr-gcc sowie den von der libc bereit gestellten
Funktionen kann man wunderbar mit C++ OO-Entwicklung auf den AVRs
betreiben. Der Code ist genauso kompakt wie in C geschriebener - was
beim Einsatz von Exceptions schon nicht mehr der Fall wäre und
insbesondere den RAM-Verbrauch extrem in die Höhe treiben würde.
War das 'Was es nicht geht:' jetzt auf avr-g++ oder arm-g++ bezogen?
BTW: Weiß jemand, ob und wie ich mit crossdev einen embedded arm
toolchain für die ARM7 von NXP emergen kann?
Ingo Elsen wrote:
> An einer Stelle möchte ich Jörg widersprechen (und im selben Atemzug für> die libc loben): C++ hat nichts mit Formel 1 zu tun ...
Das, was aber C++'lerin gewohnt war und gern hier tun wollte schon.
Mir ist schon klar, dass und warum man auch auf kleinen Controllern
C++ machen kann und will. Mir ist aber auch einigermaßen (mit meinen
beschränkten C++-Kenntnissen) klar, was man dabei tun und lassen
sollte.
Jörg Wunsch wrote:
> Das, was aber C++'lerin gewohnt war und gern hier tun wollte schon.
Völliger Unsinn.
> Mir ist schon klar, dass und warum man auch auf kleinen Controllern> C++ machen kann und will. Mir ist aber auch einigermaßen (mit meinen> beschränkten C++-Kenntnissen) klar, was man dabei tun und lassen> sollte.Mir auch. Glaub mir, ich weiß was ich tue.
Kann es sein, dass in diesem Forum ein C vs. C++ Glaubenskrieg herrscht?
Denn in keinem Beitrag hat bis jetzt jemand meine Frage richtig
beantwortet. Man hat nur C++ auf µCs niedergemacht.
C++'lerin wrote:
> Kann es sein, dass in diesem Forum ein> C vs. C++ Glaubenskrieg herrscht?
Nein.
Viele Leute würden AVRs gerne mit C++ programmieren.
Allerdings kann C++ auf einem µC in der Größenordnung
eines Mega8/16/32 seine Vorteile nicht wirklich ausspielen.
Zudem ist die typische Art und Weise wie ein µC programmiert
wird, nicht sehr C++ freundlich, sodass der Vorteil von
C++ im Vergleich zu C schnell dahinschmilzt.
Summa summarum: mit C++ gewinnt man in diesem speziellen
Umfeld nicht soviel, dass es sich lohnen wuerde.
> BTW: Weiß jemand, ob und wie ich mit crossdev einen embedded arm> toolchain für die ARM7 von NXP emergen kann?
Grundsätzlich geht das (1). Allerdings wird eine generelle
ARM-ELF-Toolchain erzeugt und keine spezielle für die NXP Targets. Als C
Library bietet sich die Newlib (2) an.
Du müsstest dafür noch die Linkercontrolskripts mit dem Speicherlayout
und an spezifische Initialisierungen angepasste Startup-Quellen
beibringen. Für einige NXP Targets gibt diese Dateien schon z.B. bei den
Examples im WinARM Paket (3). Auch bei den üblichen Verdächtigen z.B.
der LPC... Group von Yahoo dürfte es auch Beispiele für die gängigen
Targets geben.
(1) http://www.gentoo.org/proj/en/base/embedded/cross-development.xml
(2) http://sourceware.org/newlib/
(3) http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/
Also Glaubenskrieg ganz bestimmt nicht. Ich bin absoluter C++ Fan
programmiere die AVRs aber in C aus einem einzigen Grund (denn
new/delete, Exceptions und die Stdlib vermisse ich nicht):
Das Source Level Debugging im AVR Studio funktioniert nicht. Falls das
jemand Abhilfe (oder eine Alternative) kennt: Bitte sagt sie mir.
Ansonsten würde ich sofort auf C++ umschwenken, da ich in C++ besseren
Code schreibe als in C (was mehr an mir liegt als an den beiden
Sprachen).
Aber nochmal: Wozu braucht man auf einem uC wie dem AVR exceptions und
das new/delete der Standard-Bibliothek?
C++'lerin wrote:
>> Mir ist schon klar, dass und warum man auch auf kleinen Controllern>> C++ machen kann und will. Mir ist aber auch einigermaßen (mit meinen>> beschränkten C++-Kenntnissen) klar, was man dabei tun und lassen>> sollte.> Mir auch. Glaub mir, ich weiß was ich tue.
Hmm, exceptions, new/delete, late binding (vtables) -- bist du dir da
so sicher? Klar, wenn man das alles wirklich braucht, ist es in C++
effektiver programmiert als in C. Just, ich habe bislang noch nicht
so viele Controller-Applikationen erlebt, die das brauchen, und auch
die Leute, die hier am meistens in C++-Horn tuten (wie Rolf Magnus)
tun das eher wegen anderer Eigenschaften der Sprache als den von dir
benutzten/gewünschten.
Ich hätte übrigens liebend gern einen C++-Maintainer für die avr-libc
bzw. alles, was dazu gehört, aber selbst Rolf scheint wohl eher keine
Zeit dafür zu haben. :-( (Dann hätten wir auch auf dem AVR zumindest
die Möglichkeit für all die genannten Dinge, wenngleich gerade
exceptions nach meiner ersten Erfahrung heftig ins Kontor schießen,
was den ROM-Verbrauch betrifft.)
Exceptions schießen nicht nur was den ROM Verbrauch angeht ins Kontor,
sondern auch was den Stack-Verbrauch (RAM) und die Performance angeht.
Das ist den meisten Menschen, die C++ programmieren, leider nicht klar.
Hinzu kommt, dass die wenigsten die Exceptions als das sehen, was sie
eigentlich sind: Die Entsprechung zu setjmp und longjmp in C. Wer das in
seinen C-Apps für uC nicht vermisst, wird auch exceptions nicht
vermissen. Wer es in seinen C++-Apps für uC braucht, kann setjmp und
longjmp als Ersatz verwenden.
Die vtables tun nicht ganz so weh, weil die pro Klasse verwaltet werden
(im ROM) und jedes Objekt nur einen zusätzlichen Pointer auf die aktuell
gültige vtable mitbekommt. Hier sehe ich durchaus Anwendungspotenzial in
uC Applikationen (insbesondere bei den großen AVRs mit 128 und 256kByte
Flash.
> Die vtables tun nicht ganz so weh, weil die pro Klasse verwaltet werden> (im ROM) und jedes Objekt nur einen zusätzlichen Pointer auf die aktuell> gültige vtable mitbekommt. Hier sehe ich durchaus Anwendungspotenzial in> uC Applikationen (insbesondere bei den großen AVRs mit 128 und 256kByte> Flash.
dazu möchte ich einfach mal auf den Artikel:
Lean and Efficient System Software Product Lines - Where Aspects Beat
Objects
verweisen (einfach mal googeln). Ist übrigens sogar alles auf einem
ATMega implementiert.
Ciao, Fabian
Interessantes Paper. Allerdings ist mir nicht klar, wie man es hin
bekommt, den doppelten Speicherverbrauch im Vergleich zur C-Applikation
zu haben. Meines Erachtens geht das nur, wenn man viel zusätzliche
Funktionalität mit einbringt. Das ist in dem Beispiel auch
offensichtlich: Währen die C und AO Implementierung die Konfiguration
statisch vornehmen, wird es in der OO Version dynamisch gemacht. Das ist
dann in meinen Augen ein bisschen Äpfel mit Birnen verglichen.
Ingo Elsen wrote:
> Die vtables tun nicht ganz so weh, weil die pro Klasse verwaltet werden> (im ROM) ...
Nein, leider im Moment (zumindest bei AVR-GCC) im RAM. Das wäre einer
der Punkte für einen potenziellen AVR-G++-Maintainer rauszufinden,
wie man die in den ROM bringen kann (und dann mit LPM drauf zugreift).
Hm, da musst Du mir jetzt etwas auf die Sprünge helfen:
1
classA
2
{
3
public:
4
virtualvoidprint(void)
5
{
6
volatileinti=0;
7
}
8
9
virtualvoidread(void)
10
{
11
volatileinti=42;
12
}
13
};
14
15
classB:publicA
16
{
17
public:
18
virtualvoidprint(void)
19
{
20
volatileintj=1;
21
}
22
};
23
24
intmain(void)
25
{
26
volatileAa;
27
volatileBb;
28
29
return0;
30
}
assembliert bei mir zu (gekürzt):
1
.file "scratch.c"
2
.arch attiny13
3
__SREG__ = 0x3f
4
__SP_H__ = 0x3e
5
__SP_L__ = 0x3d
6
__tmp_reg__ = 0
7
__zero_reg__ = 1
8
.global __do_copy_data
9
.global __do_clear_bss
10
.section .debug_abbrev,"",@progbits
11
.Ldebug_abbrev0:
12
.section .debug_info,"",@progbits
13
.Ldebug_info0:
14
.section .debug_line,"",@progbits
15
.Ldebug_line0:
16
.text
17
.Ltext0:
18
.weak _ZTV1A
19
.data
20
.type _ZTV1A, @object
21
.size _ZTV1A, 8
22
_ZTV1A:
23
.word 0
24
.word 0
25
.word pm(_ZN1A5printEv)
26
.word pm(_ZN1A4readEv)
27
.weak _ZTV1B
28
.type _ZTV1B, @object
29
.size _ZTV1B, 8
30
_ZTV1B:
31
.word 0
32
.word 0
33
.word pm(_ZN1B5printEv)
34
.word pm(_ZN1A4readEv)
35
.text
36
.weak _ZN1A5printEv
37
.type _ZN1A5printEv, @function
38
_ZN1A5printEv:
39
.LFB2:
40
.LM1:
41
/* prologue: frame size=2 */
42
ldi r26,lo8(2)
43
ldi r27,hi8(2)
44
ldi r30,pm_lo8(.L_virtual void A::print()_body)
45
ldi r31,pm_hi8(.L_virtual void A::print()_body)
46
rjmp __prologue_saves__+32
47
.L_virtual void A::print()_body:
48
/* prologue end (size=5) */
49
.LBB2:
50
.LBB3:
51
.LM2:
52
std Y+1,__zero_reg__
53
std Y+2,__zero_reg__
54
.LBE3:
55
.LBE2:
56
/* epilogue: frame size=2 */
57
ldi r30,2
58
adiw r28,2
59
rjmp __epilogue_restores__+32
60
/* epilogue end (size=3) */
61
/* function virtual void A::print() size 10 (2) */
62
.LFE2:
63
.size _ZN1A5printEv, .-_ZN1A5printEv
64
.weak _ZN1A4readEv
65
.type _ZN1A4readEv, @function
66
_ZN1A4readEv:
67
.LFB3:
68
.LM3:
69
/* prologue: frame size=2 */
70
ldi r26,lo8(2)
71
ldi r27,hi8(2)
72
ldi r30,pm_lo8(.L_virtual void A::read()_body)
73
ldi r31,pm_hi8(.L_virtual void A::read()_body)
74
rjmp __prologue_saves__+32
75
.L_virtual void A::read()_body:
76
/* prologue end (size=5) */
77
.LBB4:
78
.LBB5:
79
.LM4:
80
ldi r24,lo8(42)
81
ldi r25,hi8(42)
82
std Y+1,r24
83
std Y+2,r25
84
.LBE5:
85
.LBE4:
86
/* epilogue: frame size=2 */
87
ldi r30,2
88
adiw r28,2
89
rjmp __epilogue_restores__+32
90
/* epilogue end (size=3) */
91
/* function virtual void A::read() size 12 (4) */
92
.LFE3:
93
.size _ZN1A4readEv, .-_ZN1A4readEv
94
.weak _ZN1B5printEv
95
.type _ZN1B5printEv, @function
96
_ZN1B5printEv:
97
.LFB4:
98
.LM5:
99
/* prologue: frame size=2 */
100
ldi r26,lo8(2)
101
ldi r27,hi8(2)
102
ldi r30,pm_lo8(.L_virtual void B::print()_body)
103
ldi r31,pm_hi8(.L_virtual void B::print()_body)
104
rjmp __prologue_saves__+32
105
.L_virtual void B::print()_body:
106
/* prologue end (size=5) */
107
.LBB6:
108
.LBB7:
109
.LM6:
110
ldi r24,lo8(1)
111
ldi r25,hi8(1)
112
std Y+1,r24
113
std Y+2,r25
114
.LBE7:
115
.LBE6:
116
/* epilogue: frame size=2 */
117
ldi r30,2
118
adiw r28,2
119
rjmp __epilogue_restores__+32
120
/* epilogue end (size=3) */
121
/* function virtual void B::print() size 12 (4) */
122
.LFE4:
123
.size _ZN1B5printEv, .-_ZN1B5printEv
124
.global main
125
.type main, @function
126
main:
127
.LFB5:
128
.LM7:
129
/* prologue: frame size=4 */
130
ldi r28,lo8(__stack - 4)
131
ldi r29,hi8(__stack - 4)
132
out __SP_H__,r29
133
out __SP_L__,r28
134
/* prologue end (size=4) */
135
.LM8:
136
ldi r24,lo8(0)
137
ldi r25,hi8(0)
138
/* epilogue: frame size=4 */
139
rjmp exit
140
/* epilogue end (size=1) */
141
/* function int main() size 7 (2) */
142
.LFE5:
143
.size main, .-main
144
.Letext0:
145
.section .debug_line
146
.long .LELT0-.LSLT0
147
148
.LSLT0:
149
.word 2
150
151
.long .LELTP0-.LASLTP0
Jetzt bin ich in AVR Assembler nicht so fit, aber liegt die vtable
_ZTV1A nicht per .word die Funktionszeiger im Textsegment an?
EDIT: Hat sich erledigt. Ich hatte das .data überlesen.
@C++'lerin:
Auf ARM7 geht vieles von c++ ohne Probleme (new, delete, ...). Aber
nicht ohne dass man einen ganzen Tag am Makefile rumspielen darf.
Erstaunlicherweise ist auch hier die Akzeptanz von c++ nicht so
besonders gut.
Vor einiger Zeit hab ich es dann doch hingekriegt einen FAT16/32
Filesystem-Driver für SD-Card zu schreiben der Objekte und Vererbung und
etc nutzt. Der code ist mit minimalen Änderungen von MSVC++ portiert
worden und dort wurde anstatt der SD-Card ein 128MB Image-File
verwendet. Es lebe c++ :-)
Liest du überhaupt noch mit?
Mfg
Gast
> Auf ARM7 geht vieles von c++ ohne Probleme (new, delete, ...).
Schön, dass endlich jemand meine Frage beantwortet. ;) Vielen Dank. :)
Und gut zu wissen, das new/delete funktioniert. Auf Exceptions kann ich
verzichten. Da tun's zur Not auch longjumps.
> Aber nicht ohne dass man einen ganzen Tag am Makefile rumspielen darf.
Was muss man denn beachten? Kannst du mal ein Beispiel-Makefile
hochladen?
> Vor einiger Zeit hab ich es dann doch hingekriegt einen FAT16/32> Filesystem-Driver für SD-Card zu schreiben der Objekte und Vererbung und> etc nutzt. Der code ist mit minimalen Änderungen von MSVC++ portiert> worden und dort wurde anstatt der SD-Card ein 128MB Image-File> verwendet. Es lebe c++ :-)
Respekt. Würdest du den Treiber mit uns teilen (Codesammlung)?
> Liest du überhaupt noch mit?
Ja, ich lese noch mit.
mit new/delete oder malloc/free würd ich bei embedded zeug aber
unheimlich aufpassen.. dein ram fragmentiert einfach zu schnell wenn du
da massiv gebrauch davon machst und dann steht deine applikation... ist
mir schon ein paar mal passiert...
73
Ja, das kenne ich. Bei malloc/free kann man dem etwas entgegenwirken,
wenn man einheitliche Blockgrößen verwendet (z.B. 16 oder 32 Byte) und
keine sehr großen Blöcke (mehr als 128 oder 256 Byte) mallociert. Für
ein dynamisches Array nimmt mann dann z.B. nicht ein großen Block (macht
Probleme beim realloc), sondern meherere keline (Stichwort: linked
list). Außerdem sollte man nach jedem malloc/realloc den Pointer checken
und gegebenenfalls Eine Fehlermeldung über LCD/UART/etc. ausgeben. Dann
weiß man wenigstens wo der Fehler liegt, und sas Programm hält nicht
einfach an.
Auf dem ARM werde ich aber mehr als genug Speicher haben, so dass ich
wohl keine Probleme mit new/delete bekommen werde.
C++'lerin wrote:
> Auf dem ARM werde ich aber mehr als genug Speicher haben, so dass ich> wohl keine Probleme mit new/delete bekommen werde.
Da hast Du schon Dein erstes!
Wenn Dein Programm häufig Datenblöcke unterschiedlicher Größe
anfordert/freigibt, kann es passieren, daß der Speicher "fragmentiert".
Das ist ein grundlegendes Problem aller Systeme, die mit dynamischer
Speicherverwaltung und ohne MMU arbeiten.
> Auf dem ARM habe ich aber wie gesagt genug Speicher, so dass das kein> Problem sein sollte.
Warum gehst du davon aus, dass du auf dem ARM genug Speicher hast? Nicht
jeder ARM ist so ein Dickschiff-ARM, wie er in PDAs vor sich hin
werkelt. Nur weil das ein 32-Bit Core ist, heißt das noch lange nicht,
dass da auch richtig viel Speicher dran ist. Nimmt man z.B. mal die LPCs
von NXP oder die SAM von Atmel, dann haben die auf dem Chip oft auch nur
8 KB Speicher. Solltest du dich als Hobby-Bastlerin mit ARMs
beschäftigen, wirst du mit sehr großer Wahrscheinlichkeit bei solchen
eher kleinen ARMs heraus kommen, weil die Entwicklungssystem für die
Dickschiffe kaum erschwinglich sind.
Ciao, Fabian
Rufus t. Firefly wrote:
> Äh, das kann auch bei "genug" Speicher ein Problem sein, das ist ja das> heimtückische daran.
Dann nimm halt noch nen Garbage-Collector dazu ;-)
Irgendwie muß man doch die Rechenleistung verpulvern.
Peter
Quatsch. Windows XP Embedded.
Wobei das noch die angenehmste Windows-Version überhaupt ist, denn die
kann auch ohne Internet Explorer, Media Player betrieben werden. Und
"aktivieren" muss/kann man die auch nicht. Dank des im Feature Pack 2007
gelieferten FBWF (file based write filter) kann man auch sehr schön mit
CF-Karten anstelle von Festplatten arbeiten. Ach, und mit
USB-Massenspeichern anstelle von Festplatten übrigens auch.
@Fabian Scheler:
Ich steige nicht auf ARM um, um wieder mit ein paar KB RAM auskommen zu
müssen. Kennst du die LPC22XX? Da kann man soviel SRAM ranhängen, wie
man will.
@rufus:
Natürlich fragmentiert der Speicher unabhängig von dessen Größe, aber
man kann trotzdem immer noch einen passenden freien Speicherblock
finden. Verstehst du? Deshalb sollte es kein Problem sein.
@peda, rufus, odblug:
Garbage-Collector, C#, Windows CE, Windows XP Embedded... werdet nicht
albern, Leute.
> Natürlich fragmentiert der Speicher unabhängig von dessen Größe, aber> man kann trotzdem immer noch einen passenden freien Speicherblock> finden.
Nein. Das bestreite ich. Sicher, es wird länger dauern, und sicher, je
nach Anwendung muss das Problem auch nicht auftreten, aber
ausgeschlossen ist es eben nicht.
Angenommen, Du hast 10 MByte Speicher zur Verfügung und füllst den mit
90 kByte großen Objekten. Dann wird jedes zweite davon wieder
freigegegeben (so daß also in Summe 5 MByte frei zu sein scheinen) und
der Versuch, auch nur einen 100 kByte-Block anzufordern, schlägt fehl.
Vereinfachte Darstellung mit einem Extremfall, zugegeben.
@C++'lerin:
Der Treiber ist nie wirklich fertiggeworden - wenn ich mich richtig
erinnere, ging zuletzt aber sogar das Erstellen von Verzeichnissen und
Dateien mit langen Dateinamen. Aber fertig ist der nie geworden leider
...
Der Treiber war für ein Projekt, das momentan "discontinued" ist:
http://home.in.tum.de/~pototsch/mp3neu/mp3_1.JPG
und
http://home.in.tum.de/~pototsch/mp3neu/mp3_2.JPG
Schreib mir doch mal eine mail, dann kriegst alles was du willst :-)
thomas.pototschnig@gmx.de
Mfg
Thomas
> Ich hätte übrigens liebend gern einen C++-Maintainer für die avr-libc> bzw. alles, was dazu gehört, aber selbst Rolf scheint wohl eher keine> Zeit dafür zu haben. :-(
Ich hab mich in letzter Zeit nicht so mit den AVRs beschäftigt. Jetzt
ist auch noch mein Programmer kaputt (ok, nicht soo ein Problem ;-) ).
Allerdings fange ich demnächst einen neuen Job an, und da wird mir
vermutlich nicht soviel Zeit bleiben. Da muß ich erstmal sehen, wie's da
wird.
> Das wäre einer der Punkte für einen potenziellen AVR-G++-Maintainer> rauszufinden, wie man die [vtables] in den ROM bringen kann (und dann> mit LPM drauf zugreift).
Es ist nicht so einfach, das zum beheben, da GCC bekanntlich nicht für
Harvard-Architekturen gedacht ist. vtables sind letztlich auch nichts
anderes als globale Variablen. Man kann nicht verschiedene Speicher
definieren, auf die mit verschiedenen Assembler-Instruktionen
zugegriffen werden kann.
Ich hatte mir mal einen Hack überlegt, mit dem's vielleicht gehen
könnte, aber ich bin im GCC-Quellcode nicht weit genug durchgestiegen,
um das mal auszuprobieren.
Rolf Magnus wrote:
> Allerdings fange ich demnächst einen neuen Job an, und da wird mir> vermutlich nicht soviel Zeit bleiben. Da muß ich erstmal sehen,> wie's da wird.
Schade. Für uns jedenfalls ;-), ich hoffe, dass du dich damit
verbesserst.
>> ..., wie man die [vtables] in den ROM bringen kann (und dann mit>> LPM drauf zugreift).> Ich hatte mir mal einen Hack überlegt, mit dem's vielleicht gehen> könnte, aber ich bin im GCC-Quellcode nicht weit genug> durchgestiegen, um das mal auszuprobieren.
Könnte man mit Björn Haase mal durchkauen, wenn du da Interesse hast.
Habe mal versucht meinen Reflexlader auf Mega8 von C nach C++ zu
portieren. Vom Quelltext her sieht C++ wesentlich ordentlicher aus.
Größen gemessen mit avr-size *.o <elfdatei>
Programm in C:
text data bss dec hex filename
28 0 0 28 1c asmfkt.o
1093 38 2 1133 46d avrreflex1.o
961 121 0 1082 43a discharge.o
608 3 0 611 263 display.o
2037 147 1 2185 889 reflex1.o
100 0 0 100 64 uuprintf.o
6744 310 90 7144 1be8 avrreflex1
Programm in C++:
text data bss dec hex filename
436 13 54 503 1f7 avrreflex2.o
20 0 0 20 14 common.o
282 0 0 282 11a display.o
1608 72 12 1692 69c timer.o
188 3 0 191 bf usart.o
100 0 0 100 64 uuprintf.o
7884 96 66 8046 1f6e avrreflex2
Betrachtet man das C Programm, dann fügt der Linker ca. 2 kBytes hinzu.
Unter C++ haben alle Funktionen des C Programms nicht in den Flash des
M8 gepasst. Deshalb habe ich solange Funkionen weggestrichen, bis es
gepasst hat. Aufblähung durch C++-Linker: Ca. 5,2 kBytes für weniger
Funktionalität.
Dazu noch eine Frage: Schreibe ich die Konstruktoren der Klassen nicht
direkt in die Klassendeklaration (Dateiendung .h), sondern in die
Dateien mit der Endung .cpp, dann legt mir avr-g++ den Konstruktor
doppelt in den Speicher bei gleichem Assembler-Code. Ist das normal,
oder ist avr-g++ noch nicht so weit, als das er das abkann.
Marco
Marco S wrote:
> Aufblähung durch C++-Linker: Ca. 5,2 kBytes für weniger> Funktionalität.
Was macht dich glauben, dass das vom Linker kommt? Es könnte genauso
gut vom Compiler sein.
Außerdem sollte man nachsehen, was genau dazu geführt hat, sicher
lässt sich das auch abändern.
> Dazu noch eine Frage: Schreibe ich die Konstruktoren der Klassen nicht> direkt in die Klassendeklaration (Dateiendung .h), sondern in die> Dateien mit der Endung .cpp, dann legt mir avr-g++ den Konstruktor> doppelt in den Speicher bei gleichem Assembler-Code. Ist das normal,> oder ist avr-g++ noch nicht so weit, als das er das abkann.
Meiner Erinnerung nach ist das normal (beide Konstruktoren sind
für verschiedene Dinge), aber ich stecke nicht genug drin um genau
zu wissen, warum das so ist. (OK, Optimiersungspotenzial wäre sicher,
die beiden zu einem zusammenzufassen, wenn sie identisch sind.)
Marco S wrote:
> Vom Quelltext her sieht C++ wesentlich ordentlicher aus.
Könntest Du dann mal beide Quelltexte hier rein stellen, damit man sie
vergleichen kann ?
Ich hab immer noch nicht kapiert, was bei C++ besser sein soll.
Wenn ich mir C++ Programme so ansehe, wird mir immer ganz schwummrig und
ich verstehe nur Bahnhof.
Da sind immer erstmal 100 Seiten Deklarationen, bevor der eigentliche
Programmcode beginnt.
Vor allem das mit der Vererbung sieht immer höllisch kompliziert aus.
Wenn ich also eine Funktion verstehen will, muß ich erstmal sämtliche
anderen Funktionen kennen, die dieser irgendwas vererbt haben. Das ist
dann ein riesen Kleister und ich kann die Funktionen nicht separat
betrachten, verstehen und debuggen.
Ich mag es aber, wenn die einzelnen Funktionen möglichst universell
sind, d.h. möglichst wenig von anderen Funktionen abhängen (wenig
Vererbung ?).
Peter
> Ich hab immer noch nicht kapiert, was bei C++ besser sein soll.
Wenn du die Sprache nicht kennst, kannst du das vermutlich auch nicht
verstehen.
Man kann mit jeder Programmiersprache natürlich Mist verzapfen, mit
manchen einfacher als mit anderen.
imho ist C++ für eingefleischte elektroniker, die vorher in C/ASM/...
programmiert haben, schwieriger zu verstehen als für 'reine'
informatiker. der höhere abstraktionsgrad (bei typischen C++
geschichten) verwirrt am anfang und die teilweise kryptische syntax
(siehe [mehrfach]vererbung) tut ein übriges. trotzdem sollte man sich
meiner meinung nach langsam mit C++ anfreunden, denn in garnicht so
ferner zukunft wird mit sicherheit vorrangig damit programmiert; fragen
nach hardware-ressourcen werden immer unwesentlicher (ich denke hierbei
nicht unbedingt an µC's).
pumpkin
@pumpkin
>meiner meinung nach langsam mit C++ anfreunden, denn in garnicht so>ferner zukunft wird mit sicherheit vorrangig damit programmiert; fragen>nach hardware-ressourcen werden immer unwesentlicher (ich denke hierbei>nicht unbedingt an µC's).
Damit hast du wohl leider Recht. :-( Und damit wird dem
Softwareoverhead, der so schon ist wie er ist nochmehr Vorschub
geleistet. Was früher (tm) aus nem P100 mit solider Programmierung lief
braucht heute "Dank" Vista, Java und Konsorten, gepaart mit
diletantischer Programmierungn nen Quadcore mit 2 GHz. Ohje.
MFG
Falk
P.S. Aber irgendwann wird es mal wieder "Back to the roots" gehen! ;-)
>> [...]diletantischer Programmierungn nen Quadcore mit 2 GHz.
naja, grafische oberflächen mit dem ganzen gebamsel hintendran frisst
halt ordentlich...
>> P.S. Aber irgendwann wird es mal wieder "Back to the roots" gehen! ;-)
wenn sich bei dem ganzen JAVA/C#/...-gedöhns dann überhaupt noch jemand
daran erinnert wie ein rechner wirklich funktioniert. ; )
mal im ernst, die hochsprachen haben imho ihre berechtigungen, moderne
anwendungen wären ohne sie schlicht undenkbar. und soooo weit weg wäre
C++ doch garnicht von den 'roots' entfernt.
pumpkin
Jörg Wunsch wrote:
>> Ich hab immer noch nicht kapiert, was bei C++ besser sein soll.>> Wenn du die Sprache nicht kennst, kannst du das vermutlich auch nicht> verstehen.
Genau deshalb wäre ja eine echte praktische Anwendung mit direkter
Vergleichsmöglichkeit äußerst lehrreich.
Die Beispiele in den C++ Lehrbüchern sind immer nur theoretisch und
total praxisfern. Daran kann man einfach nichts lernen.
Peter
@pumpkin
>mal im ernst, die hochsprachen haben imho ihre berechtigungen, moderne>anwendungen wären ohne sie schlicht undenkbar.
Auf jeden Fall! Aber so ganz koscher erscheint mir das nicht immer.
Siehe Maustreiber mit 20 MB.
> und soooo weit weg wäre>C++ doch garnicht von den 'roots' entfernt.
Kann ich nicht beurteilen.
MFG
Falk
@Falk:
wäre mir auch nicht ganz koscher. aber das hat mit sicherheit teilweise
seine berechtigung:
@Andreas:
ja, bitte! oder gib link wenn du's schonmal ausführlich gemacht hast.
danke!
@Peter:
ich denke bei embedded-geschichten an dynamische benutzeroberflächen
(z.b. menü's mit tiefe) oder modulare systeme. etwas praxisfern/selten,
meinetwegen, aber brauchbar...
pumpkin
@ Jörg
Shame on me, du hattest recht. Ich Dummerchen habe für den C++-Quellcode
den avr-g++ direkt verwendet. Warum ich das gemacht habe, keine Ahnung.
Verwende ich den avr-gcc passt das Ergebnis auch größenmäßig.
Wo liegen da eigentlich die Unterschiede zwischen avr-gcc und avr-g++?
Wenn der avr-gcc sowieso c++ schluckt, wofür gibt es dann den avr-g++?
Vielleicht bin ich ein bischen spät dran, aber das Thema hat einen
Aspekt, der bisher nicht vorkam:
Den operator new kann man auch überladen. Damit läßt sich recht elegant
das Problem mit der Speicherfragmentierung umgehen, wenn man dabei auf
Speicherpools zurückgreift, aus denen Blocks mit ähnlicher Größe
allokiert werden. Man muß dabei nicht unbedingt auf die
Standard-Heap-Implementierung von C zurückgreifen.
Zum Speicherverbrauch: Es lohnt sich, die Maplistings des Linkers näher
anzusehen, um herauszubekommen, welche Funktionen der C++ - RTL
gegenüber C dazu kommen. Dann kann man sich überlegen, ob und wie man
eigentlich nicht benötigtigte RTL-Module durch Dummies oder einfachere -
µC angepaßte - Implementierungen ersetzen kann.
Daß ganze Geschwätz über den per se unstillbaren Resourcenhunger von C++
ist jedenfalls ziemlicher Unsinn. Man kann auch so stümperhaft mit C
hantieren, daß aus einem Miniproblem ein Riesenbrocken von Programm
entsteht.
Wenn man nur C++ nach Kochbuch für Großrechner auf einem µC abgeigen
will, wirds halt nichts.
Wäre das hier eine Lösung?
http://sun.systemnews.com/articles/58/2/opt-dev/8387
Ist ein C++ -> C Transpiler.
Da ich des C++ nicht mächtig bin, habe ich keine Ahnung, ob das etwas
taugt, würde mich aber mal interessieren. Vielleicht tu ich mir dann
doch mal C++ in den Kopp...
Das ist das Konzept, nach dem die ganz frühen C++ - Compiler
funktionierten. Es ist ein Umweg, den man beim heutigen Angebot an
C++-Compilern nicht mehr gehen muß.
Der C-Code, der hinten raus kommt, ist sicher nicht der reine Genuß.
Ich würde abraten.
Der C-Code, der hinterher rauskommt, interessiert ja niemanden. Es geht
nur darum, ob man so C++ mit einem Compiler, der keine volle C++
Unterstützung hat, verwenden kann.
Ich schau mir den Assembler-Code, der bei einem C-Compilat hinten
rauskommt, eigentlich auch nur noch sehr selten an ;)
Uhu Uhuhu wrote:
> Das ist das Konzept, nach dem die ganz frühen C++ - Compiler> funktionierten. Es ist ein Umweg, den man beim heutigen Angebot an> C++-Compilern nicht mehr gehen muß.>> Der C-Code, der hinten raus kommt, ist sicher nicht der reine Genuß.>> Ich würde abraten.
Seh ich auch so.
Ein 'richtiger' C++ Compiler kann dann auch noch ein paar
Optimierungen machen (zb. named return value optimization)
die bei einer vorhergehenden Übersetzung nach C wahrscheinlich
auf der Strecke bleiben würden. Vor allem mit dem Referenz
Konzept sind da noch ein paar Optimierungen möglich.
Die meisten Tests auf Desktop Ebene haben (hatten) zum
Ergebnis dass in C++ geschriebene Programme meistens nicht größer
oder zumindest nicht viel größer sind als gleichwertige C Programme,
aber oft etwas schneller ablaufen. Die grosse Ausnahme ist meist,
wenn die I/O streams benutzt werden. Soll aber auch schon besser
werden.
Ein Beispiel:
Ihr kennt doch alle die Funktion qsort():
Quicksort der man einen Callback übergibt, der für das Vergleichen
von 2 Items zuständig ist.
Macht man das in C++ Manier, dann benutzt man das std::sort()
aus algorithm.h. Der braucht natürlich auch eine Vergleichs-
funktionalität. Da std::sort aber ein Template ist, kann der
Compiler den Vergleich direkt in den Sortieralgorithmus einbauen
und spart sich so den Call-Overhead einer Vergleichsfunktion.
Was auch oft übersehen wird: C++ Code ist meist robuster, da das
Fehlerhandling konsequenter durchgezogen wird (RAII lässt grüßen).
C Programmierer sind da oft notorisch faul und schon vergleicht
man Äpfel mit Birnen: Ein C++ Programm, dass auch mit Problemen
noch gut zurecht kommt mit einem C Programm das bei der geringsten
Kleinigkeit nur noch Unsinn macht. Und wir alle wissen:
Es ist nicht ungewöhnlich, dass Fehlerbehandlung mehr Code braucht
als der reine 'Arbeitscode'.
Der C++ -> C Precompiler ist eigentlich nur dann sinnvoll, wenn man
bestehenden C++ - Code in eine Umgebung portieren will, für die es
keinen (brauchbaren) C++ - Compiler gibt, aber ein C-Compiler zur
Verfügung steht.
Ich würde das Teil sofort verwenden, um C++ - Programme auf meinem
Taschenrechner zum Laufen zu bringen - nur leider habe ich für den noch
keinen C-Compiler gefunden. Aber das kann ja noch werden...
> Macht man das in C++ Manier, dann benutzt man das> std::sort() aus algorithm.h.
Kleine Korrektur: Du meinst den header algorithm.
Mit .h gibt es den laut Standard nicht.
> Macht man das in C++ Manier, dann benutzt man das std::sort()> aus algorithm.h. Der braucht natürlich auch eine Vergleichs-> funktionalität. Da std::sort aber ein Template ist, kann der> Compiler den Vergleich direkt in den Sortieralgorithmus einbauen> und spart sich so den Call-Overhead einer Vergleichsfunktion.
Das hat allerdings immernoch den Nachteil, das sort nur O(n)=n log n
Algorithmen implementieren kann.
arc wrote:
>> Macht man das in C++ Manier, dann benutzt man das std::sort()>> aus algorithm.h. Der braucht natürlich auch eine Vergleichs->> funktionalität. Da std::sort aber ein Template ist, kann der>> Compiler den Vergleich direkt in den Sortieralgorithmus einbauen>> und spart sich so den Call-Overhead einer Vergleichsfunktion.>> Das hat allerdings immernoch den Nachteil, das sort nur O(n)=n log n> Algorithmen implementieren kann.
Hast du den Rest gelesen?
Darum geht es doch gar nicht. Es geht darum welche Möglichkeiten
der Optimierung ein C++ Compiler im Vergleich zu einem C Compiler hat.
Bleib doch bitte ein bischen beim Thema.
> Hast du den Rest gelesen?> Darum geht es doch gar nicht. Es geht darum welche Möglichkeiten> der Optimierung ein C++ Compiler im Vergleich zu einem C Compiler hat.> Bleib doch bitte ein bischen beim Thema.
Ist denn sichergestellt bzw. kann sichergestellt werden, daß die
Vergleichsoperation inline ausgeführt wird und nicht doch als normaler
Funktionsaufruf übersetzt wird? Erzeugt jeder Compiler/Linker nur die
erforderlichen Spezialisierungen?
Der beste Optimierer sitzt (z.Z.) immernoch vor dem Rechner.
Die Aufgabe eines Optimierers ist nicht, aus einem vergurkten
Algorithmus den bestmöglichen zu machen.
Die Idiotie, auf einem reinen Integer-µC Sensorwerte mit
Fließkommaarithmetik zu behandeln, kann er auf keinen Fall glatt
bügeln...
Uhu Uhuhu wrote:
> Die Idiotie, auf einem reinen Integer-µC Sensorwerte mit> Fließkommaarithmetik zu behandeln, kann er auf keinen Fall glatt> bügeln...
Wenn relativ komplizierte Berechnungen notwendig sind, aber die
Geschwindigkeit keine Rolle spielt, dann ist es Idiotie KEINE
Fließkommaarithmetik zu verwenden.
Andreas Schwarz wrote:
> Wenn relativ komplizierte Berechnungen notwendig sind, aber die> Geschwindigkeit keine Rolle spielt, dann ist es Idiotie KEINE> Fließkommaarithmetik zu verwenden.
Vergleicht man Auflösung und Wertebereich gängiger Sensoren mit denen
der Datentypen float oder double, fällt auf, daß da ein ziemliches
Mißverhältnis besteht.
Rechnet man den Sensorwert in ein Fließkommaformat um, gewinnt man nicht
Genauigkeit, sonden Rauschen.
Dieses Rauschen bezahlt man auch noch mit einem um Größenordnungen
erhöhten Bedarf an Rechenleistung - m.a.W.: Man heizt, nur weil man
vorher nicht gedacht hat.
Mit etwas Überlegung lassen sich alle derartigen Probleme mit
Integer-Datentypen berechnen.
Die Mathematik nicht zu berherrschen, um eine Problemlösung per
int-Artihmentik zu realisieren, ist jedenfalls das allerletzte Argument
für den Einsatz von Fließkomma.
Grundregel beim Programmieren: optimiert wird dann, wenn es nötig ist.
Also schreibt man eine komplizierte Rechnung einfach erst mal in Float
hin, statt Zeit in eine Integerimplementierung zu stecken. Wenn sich
dann herausstellt dass das zu groß oder zu langsam ist kann man immer
noch umsteigen. Wenn die Berechnung aber nur einmal pro Sekunde benötigt
wird ist es völlig irrelevant ob sie 10 µs oder 1 ms dauert; wichtiger
ist, dass man mit einem Blick sehen kann was gerechnet wird, und auch
einfach Änderungen vornehmen kann, statt sich durch einen unnötigen Wust
von Bitschiebereien und ähnlichem kämpfen zu müssen.
Wenn der Programmspeicher kleiner als die Float-Bibliothek ist verbietet
sich Float natürlich von vornherein; aber bei einem Controller mit zig
kB Flash spielt ein konstanter Overhead von 2-4 kB meistens keine Rolle.
Andreas Schwarz wrote:
> Grundregel beim Programmieren: optimiert wird dann, wenn es nötig ist.> Also schreibt man eine komplizierte Rechnung einfach erst mal in Float> hin,
Das kommt drauf an wie kompliziert die Berechnung tatsächlich ist.
Ist sie nur kompliziert genug, dann öffnet sich mit der Verwendung
von float (anstatt double, dass es leider in WinAVR nicht gibt)
ein ganzer Sack neuer Probleme.
Und um keine Missverständnisse aufkommen zu lassen: Ein richtiger
double behebt diese Probleme nicht. double macht sie nur etwas
kleiner.
Wer noch nie in einer komplexen Berechnung nach Rundungsfehlern
gesucht und nach Wegen geforscht hat, sie zu umgehen, möge sein
Glück preisen. Die anderen wissen wovon ich rede.
http://docs.sun.com/source/806-3568/ncg_goldberg.html
Ungefähr in der Mitte des Textes ist ein Kapitel 'Optimizers'.
Wenn auch der Rest eher theoretischer Natur ist, (nichts desto
trotz ist der aber wichtig), so zeigt dieses Kapitel was bei
naiver Hintipperei von floating point Ausdrücken so alles passieren
kann.
> Grundregel beim Programmieren: optimiert wird dann, wenn es nötig ist.
Die kann aber nicht gründliche Systemanalyse und Planung vor der
Implementierung ersetzen.
Der unüberlegte Einsatz von Fließkommaformaten dürfte einer der
verbreitetsten Anfängerfehler sein.
Das Problem der Fließkommaformate ist, daß Programmierer sie gerne für
eine technische Realisierung Reeller Zahlen halten.
In Wirklichkeit verhalten sie sich ganz und garnicht so und Numeriker
können die tollsten Beispiele dafür vorführen - siehe obigen Link von
Karl heinz Buchegger.
Zudem sind die Vorgänge in einem float/double-Emulator für Programmierer
ziemlich undurchsichtig und folglich das Resultat zumindest unsicher.
Das Gegenmodell: Mathematische Analyse des Problems und Approximation
der benötigten Berechnungen mit int-Typen, incl. einer
Fehlerabschätzung.
Packt man diese int-Approximation in den µC, weiß man genau, was man von
den Daten, die hinten heraus kommen, zu halten hat.
Die Vorgehensweise läßt sich sicherlich systematisieren und sogar
automatisieren - vielleicht gibt es ja schon solche Generatoren...
Die float/double-Rechnung liefert jedenfalls keine Fehlerabschätzung.
Eine Fehlerrechnug dafür zu erstellen, wird beliebig kompliziert.
Dass Fließkomma ein Allheilmittel ist hat niemand behauptet. Aber nehmen
wir doch mal ein konkretes Beispiel: Taupunktberechnung. Mit Float
(double oder single spielt erst in der 5. Nachkommastelle eine Rolle)
sind das ein paar Zeilen Code, in Festkomma darf man sich erst mal
Gedanken machen wie man den Logarithmus implementiert - wenn man noch
genug Platz im Flash hat ist das einfach nur Zeitverschwendung.
Andreas Schwarz wrote:
> Dass Fließkomma ein Allheilmittel ist hat niemand behauptet.
Das haben wir dir auch nicht unterstellt.
Nur halte ich die Aussage
> Also schreibt man eine komplizierte Rechnung einfach erst mal> in Float hin,
für eine gewagte Aussage, die ich so einem Newbie nicht unterbreiten
würde. Vor allem das Wort 'einfach' im Zusammenhang mit
'komplizierter Berechnung' stört mich da drinnen.
Karl heinz Buchegger wrote:
> Andreas Schwarz wrote:>> Also schreibt man eine komplizierte Rechnung einfach erst mal>> in Float hin,>> für eine gewagte Aussage, die ich so einem Newbie nicht unterbreiten> würde. Vor allem das Wort 'einfach' im Zusammenhang mit> 'komplizierter Berechnung' stört mich da drinnen.
Mit "komplizierte Berechnung" meine ich: alles was über ein paar
Multiplikationen und Additionen hinausgeht. Mit "einfach hinschreiben"
meine ich: man kann die Formeln aus der Mathematik/Physik einfach
runterschreiben und es funktioniert.
Andreas Schwarz wrote:
> Aber nehmen> wir doch mal ein konkretes Beispiel: Taupunktberechnung. Mit Float> (double oder single spielt erst in der 5. Nachkommastelle eine Rolle)> sind das ein paar Zeilen Code, in Festkomma darf man sich erst mal> Gedanken machen wie man den Logarithmus implementiert - wenn man noch> genug Platz im Flash hat ist das einfach nur Zeitverschwendung.
Natürlich hat floating point seinen Stellenwert und bei der
von dir genannten Aufgabenstellung macht es wahrscheinlich
auch keinen Sinn da was anderes zu bemühen. Oder doch?
Ich kenne die Formel nicht und weis nicht wie sich ein Taupunkt
berechnet.
Das ist ja die Krux an floating point Problemen: Jedes Problem
ist anders und jedes Problem muss für sich alleine analysiert
werden ob Rundungsfehler sich auswirken oder nicht.
Damit haben aber gerade Neulinge ein riesiges Verständnisproblem
(mal ganz abgesehen von der "Die Zahl kommt aus dem Computer, die
muss stimmen!" - Mentalität)
Andreas Schwarz wrote:
> Karl heinz Buchegger wrote:>> Andreas Schwarz wrote:>>> Also schreibt man eine komplizierte Rechnung einfach erst mal>>> in Float hin,>>>> für eine gewagte Aussage, die ich so einem Newbie nicht unterbreiten>> würde. Vor allem das Wort 'einfach' im Zusammenhang mit>> 'komplizierter Berechnung' stört mich da drinnen.>> Mit "komplizierte Berechnung" meine ich: alles was über ein paar> Multiplikationen und Additionen hinausgeht. Mit "einfach hinschreiben"> meine ich: man kann die Formeln aus der Mathematik/Physik einfach> runterschreiben und es funktioniert.
Wenn es nur so einfach wäre:
Wenn in derselben Formel sehr grosse und sehr kleine Zahlen
gleichzeitig vorkommen, hast du ein Problem. Das fängt schon
bei einer einzigen Addition an:
1234567.890 + 0.01
wird mit float nicht das gewünschte Ergebnis bringen.
> Mit Float (double oder single spielt erst in der 5. Nachkommastelle> eine Rolle) sind das ein paar Zeilen Code, in Festkomma darf man sich> erst mal Gedanken machen wie man den Logarithmus implementiert.
Nein. Man muß sich nicht überlegen, wie man in int den Logarithmus
implementiert und die Tatsache, daß das Problem erst mit der 5.
Nachkommastelle lebendig wird, ist kein Argument für den Einsatz von
float & Co.
Wenn man sich eine Lookup Tabelle baut, die die Sensorwerte auf den
jeweiligen Meßwert abbildet, dann verschindet der Logarithmus dort drin
und der µC merkt nichts davon.
Das mit der 5. Nachkommastelle ebenso.
Die Größe der LUT ergibt sich dabei aus der Dynamik der zugrunde
liegenden Funktion, den Genauigkeitsanforderungen an die Approximation
und dem benutzten Interpolationsverfahren, mit dem Zwischenwerte
berechnet werden.
Das Denken ersetzten Float-Zahlen auch nicht, aber wenn er ein paar
Grundregeln beachtet kann auch der Neuling Float sinnvoll anwenden. Bei
Integer gibt es genauso Fallstricke: Überläufe in Teilausdrücken, 1/10 *
100 == 0, signed vs. unsigned, usw.
Wie auch immer, ich wollte nur der Aussage widersprechen, dass die
Verwendung von Soft-Float auf einem µC "Idiotie" wäre.
Uhu Uhuhu wrote:
> Das Problem der Fließkommaformate ist, daß Programmierer sie gerne für> eine technische Realisierung Reeller Zahlen halten.>> In Wirklichkeit verhalten sie sich ganz und garnicht so und Numeriker> können die tollsten Beispiele dafür vorführen - siehe obigen Link von> Karl heinz Buchegger.
Und trotzdem wirst du keinen Numeriker finden, der Numerikprobleme in
Integerrechnung löst, wenn es nicht wegen Einschränkungen der Hardware
nötig ist.
> Die Größe der LUT ergibt sich dabei aus der Dynamik der zugrunde> liegenden Funktion, den Genauigkeitsanforderungen an die Approximation> und dem benutzten Interpolationsverfahren, mit dem Zwischenwerte> berechnet werden.
Und die Bilanz?
- >10-fache Menge an Code
- >10-facher Zeitaufwand
- schlechtere Genauigkeit
- 2 kB Flash gespart.
> Wie auch immer, ich wollte nur der Aussage widersprechen, dass die> Verwendung von Soft-Float auf einem µC "Idiotie" wäre.
Nun gut, ich gebe gerne zu, daß meine Ausdrucksweise etwas überspitzt
war und nicht für alle Fälle gilt.
Allerdings sind die fachlich gerechtfertigten praktischen Einsätze davon
um mehrere Zehnerpotenzen seltener, als man es hier im Forum feststellen
kann.
Für den Rest gilt: Bestenfalls zu unerfahren...
Uhu Uhuhu wrote:
> Allerdings sind die fachlich gerechtfertigten praktischen Einsätze davon> um mehrere Zehnerpotenzen seltener, als man es hier im Forum feststellen> kann.
Das ist allerdings möglich (es wurde hier auch schon mal in
Fließkommarechnung implementierte Tastenentprellung gesichtet).
> Und trotzdem wirst du keinen Numeriker finden, der Numerikprobleme in> Integerrechnung löst, wenn es nicht wegen Einschränkungen der Hardware> nötig ist.
Numeriker werden sich kaum mit Problemen auseinandersetzten, die grade
mal lumpige 1-4 k verschiedene Zustände haben - wenn es sich um
Dimensionen handelte, wäre das was anderes.
Für Massenprodukte spielt es u.U. eine entscheidende Rolle, ob das
Problem mit einem kleinen, oder einem großen µC gelöst wird; die
Einschränkungen i.S. Hardware sind also immer gegeben, es sei denn man
bastelt irgendwas für sich selbst, oder plant den großen
wirtschaftlichen Flopp.
> - schlechtere Genauigkeit
Das ist blanker Unsinn. Du solltest Dich dringend mit der Materie
auseinandersetzen.
> (es wurde hier auch schon mal in Fließkommarechnung implementierte> Tastenentprellung gesichtet).
Ich habe letzhin einen Stackoverflow in einem Dateisystem analysiert.
Ursache war eine rekursiv programmierte Wait-Funktion...
Uhu Uhuhu wrote:
>> Und trotzdem wirst du keinen Numeriker finden, der Numerikprobleme in>> Integerrechnung löst, wenn es nicht wegen Einschränkungen der Hardware>> nötig ist.>> Numeriker werden sich kaum mit Problemen auseinandersetzten, die grade> mal lumpige 1-4 k verschiedene Zustände haben - wenn es sich um> Dimensionen handelte, wäre das was anderes.
Andererseits spielt bei diesen 1-4 k verschiedenen Zuständen auch deine
Fehlerabschätzung keine Rolle.
> Für Massenprodukte spielt es u.U. eine entscheidende Rolle, ob das> Problem mit einem kleinen, oder einem großen µC gelöst wird; die> Einschränkungen i.S. Hardware sind also immer gegeben, es sei denn man> bastelt irgendwas für sich selbst, oder plant den großen> wirtschaftlichen Flopp.
Wie gesagt: wenn sich herausstellt dass Float zu groß ist, dann kann man
immer noch auf Integer umsteigen. Wenn sich herausstellt dass am Ende
noch 10 kB Flash übrig sind, dann hat man mit Integer Zeit verschwendet.
>> - schlechtere Genauigkeit>> Das ist blanker Unsinn. Du solltest Dich dringend mit der Materie> auseinandersetzen.
Du solltest mal von deinem hohen Ross runterkommen.
Hier würde ich auch keine Klimmzüge machen, um das ohne FPs zu
berechnen, da sich die Parameter nur (relativ) langsam ändern können,
die Ausgabe auf einem Display nur selten vorkommt oder man das ganze
auch bequem nachträglich im PC berechnen kann.
p.s. diesmal ohne \\ oder \newline
Die mathematische Beschreibung des Problems gilt mit Sicherheit nicht
für alle reellen Zahlen.
Eine technische Realisierung ist erst dann sinnvoll möglich, wenn die
Randbedingungen klar definiert sind.
Was ist T, rH?
In welchen Wertebereichen fallen sie an?
Welche Auflösung?
Jeweils in Sensorwerten, nicht irgendwelche FP-Zahlen!
T = Temperatur, rH = relative Luftfeuchtigkeit
Wertebereiche: Temperatur z.B. im Bereich -30 °C - 30/50 °C, rH 0..1
Hinzukommen div. Fallunterscheidungen (z.B. über Wasser/Eis).
(U.U. auch andere Eingangsgrößen wie absolute Feuchte statt rH,
Sättigungsdrücke, Partialdrücke etc.)
Sinnvolle Auflösungen: Temperatur 0.1 °C, rH 0.1% (eher 1%)
Unsicherheit der genannten Formel: +-0.4 °C (0 °C < T < 60 °C und 0 < rH
< 1)
Damits nicht ganz so einfach wird: Keine digitalen
Feuchte/Temperatursensoren,
sondern eher PT100/PT1000 oder Thermoelemente und kapazitive
Feuchtesensoren.
Also um nochmal zur ursprünglichen Frage zurückzukommen, ich wäre auch
interessiert einen AVR in C++ ohne libc++ o.Ä. zu programmieren, einfach
nur um die Klassensyntax auszunutzen. Klar geht das alles "im Prinzip"
auch in C, aber wenn ich nur Klassen verwende (und nur auf Referenzen
beim Übergeben setze) habe ich IMHO ja keinen Overhead.
Kann man die new() und delete() operatoren einfach selbstdefinieren und
an malloc() und free() weiterleiten? Eigentlich müsste dies ja gehen.
Klar geht das, das sind einfache Operatoren die du überladen kannst.
Aber ehrlich gesagt halte ich es für ziemlichen Dummfug auf einem uC mit
C++ loszulegen. Namespaces sind das einzige das man sinnvoll auf einem
uC einsetzen kann, aber das wars dann schon wieder.
Und nein, ich bin kein C Verfechter, ich programmier sogar recht gern in
C++ und benutze auch oft Templates und artverwandtes, größere Projekte
fang ich in reinem C garnet erst an.
Auf einem Mikrocontroller ist reines C aber ganz einfach sinnvoller.
Das ist aber allgemein ein Problem bei der Softwarentwicklung, da werden
teilweise performancekritische Sachen schön sauber in Klassen verpackt
damit der Code elegant ausschaut, und ohne Klassen wär die Geschichte
10mal so schnell.
Dann werden neue Rechner angeschafft, weil der Code in C++ zu langsam
ist... und Javianer kommen auf die absurde Idee ihre Sprache wär
schneller.
Naja, wenn ich statt structs Klassen verwende, und nur das von c++, habe
ich ja IMHO keinen Overhead bezüglich Speicher. Und das Referenzieren
des this-Zeigers in Methoden sollte ja nicht so schlimm sein.
Ich sehe das Ganze nicht als C++, sondern eher als C++-Light, Klassen,
eventuell Namespaces und das wars. Klar mit ner stdlib braucht man auf
sonem yC gar nicht anzufangen.