Forum: Compiler & IDEs (ARM) GCC binary size viel größer als von Realview


von Philipp_M (Gast)


Lesenswert?

Hallo,

Ich hantiere derzeit mit einem STM32 Cortex M4 Eval Board von Waveshare, 
und experimentiere mit jenen bereitgestellten Beispielen, wie dem 
LCD-Display, SRAM etc.

Dazu hab ich bisher das bereitgestellte MDK von KEIL genommen, welches 
ja mit dem built-in Realview Compiler daherkommt, der in der freien 
Version bis zu 32kb binary Size generiert.

Allerdings möchte ich nicht an Windows gebunden sein, und habe mir unter 
Linux mittels der Anleitung aus dem Wiki eine Eclipse Umgebung 
eingerichtet.
Das Ganze funktioniert auch eigentlich super, Debugging funktioniert gut 
(wenn auch ein wenig langsam) mit dem STlink 2. Dort verwende ich das 
GCC Embedded Tools von Launchpad.
Ich hatte zwischenzeitlich auch die Sourcery Bench Lite Version am 
laufen gehabt, aber nach dem ich die Einschränkung bezüglich FPU 
Funktionalität gesehen habe, bin ich dann auf das freie GCC gewechselt.

Naja ich erwähne das eigentlich nur, um zu sagen, dass dort das gleiche 
Problem war, zu dem ich jetzt komme.

Bei Realview entstehen binary sizes von ca. 8-27kb mit den Beispielen 
von Waveshare. Und beim GCC gibt es Größen, von 64kb-100kb.

Ich denke GCC fügt noch viel unnötige Bibliotheken in die binary ein. 
Darauf hab ich dann verschiedene Compiler Optimierungsoptionen 
eingefügt, welche zwar marginal was gebracht haben(ca. 10-20kb weniger) 
aber trotzdem das Ganze noch immer viel zu groß ist.
Hier die Compiler Optionen:

Realview CC:
1
--feedback "Project.fed" -c --cpu Cortex-M4.fp -D__EVAL -g -O2 -Otime 
2
--apcs=interwork -I..\User -I..\Libraries\STM32F4xx_StdPeriph_Driver\inc 
3
-I..\Libraries\CMSIS\Include 
4
-I..\Libraries\CMSIS\Device\ST\STM32F4xx\Include -I P:\Keil\ARM\RV31\Inc 
5
-I P:\Keil\ARM\CMSIS\Include -I P:\Keil\ARM\Inc\ST\STM32F4xx -DSTM32F4XX 
6
-DUSE_STDPERIPH_DRIVER -o "*.o" --omf_browse "*.crf" --depend "*.d"

Realview Linker:
1
--cpu Cortex-M4.fp *.o --feedback "Project.fed" 
2
--strict --scatter "Project.sct"

GCC CC:
1
-c -mthumb -gdwarf-2 -MD -Wall -Os -I../User 
2
-I../Libraries/STM32F4xx_StdPeriph_Driver/inc 
3
-I../Libraries/CMSIS/Include 
4
-I../Libraries/CMSIS/Device/ST/STM32F4xx/Include -mcpu=cortex-m4 
5
-mfloat-abi=softfp -mfpu=fpv4-sp-d16 -ffunction-sections 
6
-fdata-sections -IP:/Keil/ARM/CMSIS/Include 
7
-IP:/Keil/ARM/Inc/ST/STM32F4xx -DSTM32F4XX -DUSE_STDPERIPH_DRIVER 
8
-DHSE_VALUE="8000000" -Wa,-alhms="*.lst" -o *.o

GCC Linker:
1
-T ./stm32_flash.ld -mthumb -Wl,-Map="./Project.map" 
2
-o Project.elf -gc-sections, -s

Wie man oben sieht nutze ich für GCC "stm32_flash.ld" aus der StdPeriph 
Lib.
Wenn Bedarf besteht, kann ich auch noch mal die beiden Projekte(GCC, 
Realview) hochladen.

Ach ja der Grund warum ich so an Code-size "geize" ist, dass ich für den 
Anfang wegen der beschränkten Schreibanzahl im Flash lieber im SRAM 
arbeite, und erst wenn es wirklich notwendig wird, auf den Flash 
umsteige.

Vielen Dank schon mal
Philipp

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Die Größe der Binaries machst Du an deren Dateigröße fest, oder 
untersuchst Du die mit dem Mapfile oder ähnlichem?

Zumindest beim gcc erzeugst Du eine .elf-Datei, das ist kein "nacktes" 
Binary, also nicht 1:1 das Abbild eines Flash-ROM o.ä., sondern kann 
noch diversen weiteren Kram enthalten, wie z.B. auch 
Debug-Informationen.

von Karl (Gast)


Lesenswert?

Äpfel - Birnen
softfp - hardfp
newlib - whateverlib
Kostenlos - einige k€

Schau doch mal nach, was den vielen Platz verbraucht.

Abgesehen davon: Den Controller durch Neuprogrammieren totzuflashen muss 
man auch erstmal schaffen.

von Heiko J. (heiko_j)


Lesenswert?

Karl schrieb:
> Kostenlos - einige k€
>
> Schau doch mal nach, was den vielen Platz verbraucht.

Falls die k€ zu viel Platz verbrauchen würde ich sie dir auch abnehmen. 
Auf meinem Konto ist noch viel Platz :-)

von Philipp_M (Gast)


Lesenswert?

@Rufus

Ich vergleiche denke ich schon die richtigen Größen, also die, die der 
"size-analyzer" der jeweiligen Toolchains ausgibt. Also beim GCC z.B.
1
arm-none-eabi-size  --format=berkeley LCD-Driver.elf
2
   text     data      bss      dec      hex  filename
3
 176152     2180     1088   179420    2bcdc  LCD-Driver.elf
(dort ist allerdings ein 136320 Byte großes Bild im Flash gespeichert, 
um Verwirrung vorzubeugen)

@Karl
Ob es ein Äpfel-Birnen Vergleich ist, sei mal dahin gestellt.
Es werden zwei Compiler verglichen, mit dem selben Output, und 
float-Zahlen sind bei vielen der getesteten Beispiele nicht vorhanden.

Aber der Rest den du meinst leuchtet mir schon ein. Ich dachte 
eigentlich, dass der GCC Compiler sogar bessere Arbeit verrichtet, aber 
mit den Argumenten, ist das wirtschaftlich natürlich Unsinn(wer würde 
dann noch RealView kaufen)
Also ist der GCC einfach doch zu "generell", um sehr (größen)optimierten 
Code zu erzeugen...

Karl schrieb:
> Schau doch mal nach, was den vielen Platz verbraucht.

Jetzt muss ich mich leider doof stellen, wie geht das?

Gruß
Philipp

von (prx) A. K. (prx)


Lesenswert?

Philipp_M schrieb:
> Jetzt muss ich mich leider doof stellen, wie geht das?

Ins Mapfile vom Linker reinsehen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Philipp_M schrieb:

> Aber der Rest den du meinst leuchtet mir schon ein. Ich dachte
> eigentlich, dass der GCC Compiler sogar bessere Arbeit verrichtet, aber
> mit den Argumenten, ist das wirtschaftlich natürlich Unsinn(wer würde
> dann noch RealView kaufen)

Die Leute, die glauben, dass man für mehr Geld automatisch einen
besseren Compiler bekäme.  Oder Leute, die einen Compiler mit einer
IDE verwechseln und einen bestimmten Compiler deshalb bevorzugen, weil
sie die mit ihm üblicherweise gemeinsam angebotene IDE gut finden.

> Also ist der GCC einfach doch zu "generell", um sehr (größen)optimierten
> Code zu erzeugen...

Keineswegs.

Ohne eine genaue Analyse kann man aber nicht viel sagen.  Am besten
wäre es natürlich, wenn du die Codegrößen für einzelne Funktionen
zwischen beiden Compilern vergleichen könntest.  Bei den GNU-Tools
geht das mit “arm-none-eabi-nm --print-size” (ggf. noch --size-sort
mit angeben).

von Martin T. (mthomas) (Moderator) Benutzerseite


Lesenswert?

Irgendwo im Code in printf/sprintf? Falls ja, erstmal durch 
iprintf/siprintf ersetzen oder auskommentieren, wenn dies eine deutliche 
Änderung der Codegröße bringt, ist der "Übertäter" eingegrenzt. stdio 
und insbes. stddio mit FP sind in der newlib zwar universell aber 
speicherhungrig. Es existieren schlankere Implementierungen. Ansonsten: 
mehr Informationen liefern. Code, Linker-Script und Makefile 
zusammenpacken und einstellen.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Falls du C++ verwendest: -fno-exceptions , -fno-rtti, eine leere 
Funktionen "__cxa_pure_virtual" (mit extern "C", falls in einem C++ 
Sourefile) einbauen. C++11 verwenden, so viele Konstruktoren wie möglich 
"constexpr" machen.

Auch für C:
* Den ARM Compiler mit LTO neu compilen (oder hier 
http://games.2g2s.de/zeug/gcc-arm-none-eabi-4_7-2013q1-20130320-linux.tar.bz2 
von mir ein Binary für Linux loaden) und beim linken deines Programms 
-flto angeben. Dies erfordert, dass du alle Compiler Flags auch beim 
Linken angibst.
* Mit "-ffunction-sections -fdata-sections" compilen und linken, mit 
-Wl,--gc-sections linken.
* Da du ja einen Cortex-M4F hast (mit FPU), solltest du auch das hardfp 
ABI verwenden: "-mfpu=fpv4-sp-d16 -mfloat-abi=hard" beim Compilen und 
linken
* Leere Funktion "atexit" einbauen.
* Mit -Os compilen und linken.
* Die Inlining-Heuristik vom GCC ist nicht so gut, bei kleinen 
Funktionen überlegen ob inlinen grundsätzlich sinnvoll ist (zB weil der 
Aufruf-Aufwand schon groß wäre), und dort "__attribute__( ( 
always_inline ) )" verwenden.
* Möglichst viele Berechnungen vom Compiler anstellen lassen durch 
Verwendung von "const" und "constexpr". Dazu auch "union" statt 
Pointer-Magic verwenden, damit der Compiler "sieht" was man vorhat.
* ggf. uint_fast8_t statt uint8_t verwenden etc.
* Wie oben schon genannt, printf und andere hungrige Library-Funktionen 
vermeiden.
* Mehrere aufeinanderfolgende Zugriffe auf dieselbe "volatile" Variable 
vermeiden, da diese natürlich nicht optimiert werden können/dürfen (Die 
ST StdPeriphal Library z.B. macht das leider)

Und am wichtigsten natürlich, mit "objdump -d foo.elf" den generierten 
Code disassemblen und ansehen. Dabei auf Funktionen wie 
"_ZN5STM323RCC6ClocksL6SYSCLKE.5950.4626" achten, die sind ein Hinweis 
auf nicht vernünftig optimierte (constexpr) C++ Konstruktoren. Auch 
nachsehen welche Library Funktionen im Binary landen, von welcher in 
deinem Code verwendeten Funktion diese benötigt werden, und überlegen ob 
diese so zwingend erforderlich sind (wie printf oben).

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Niklas Gürtler schrieb:
> * Die Inlining-Heuristik vom GCC ist nicht so gut,
selbst wenn man "inline" dranschreibt ignoriert der GCC das gerne mal, 
wollte ich noch schreiben, aber hier gibts ja das 15min-Limit.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Philipp_M schrieb:
> Ich vergleiche denke ich schon die richtigen Größen, also die, die der
> "size-analyzer" der jeweiligen Toolchains ausgibt. Also beim GCC z.B.
>
> arm-none-eabi-size  --format=berkeley LCD-Driver.elf
>    text     data      bss      dec      hex  filename
>  176152     2180     1088   179420    2bcdc  LCD-Driver.elf

Wende die Size-Tools mal nicht auf das gesamte Programm (*.elf), sondern
auf einzelne Objektmodule (*.o) an. Wenn dort die Unterschiede zwischen
den beiden Compilern geringer sind (was ich fast vermute), liegt die
Ursache des drastisch schlechteren Abschneidens des GCC (auch) in den
verwendeten Laufzeitbibliotheken. Beim Keil-Compiler hast du die Auswahl
zwischen der ARM-Standard-Library und der MicroLib. Letztere ist nicht
so sehr geschwindigkeitsopimiert und in der Funktionalität einiger
Funktionen eingeschränkt, dafür ist der mit ihr gelinkte Code deutlich
kompakter:

  http://www.keil.com/arm/microlib.asp
  http://www.keil.com/support/man/docs/armlib/armlib_bajjibhh.htm

von Uwe B. (derexponent)


Lesenswert?

Hi Philipp,

unabhängig von deinem Problem
muss ich Karl rechtgeben :

>Abgesehen davon: Den Controller durch Neuprogrammieren totzuflashen muss
>man auch erstmal schaffen.

das Flash hält 10.000 Schreibzyklen aus
ich glaube du machst dir da unnötig sorgen

Gruss Uwe

von Philipp_M (Gast)


Lesenswert?

Hui,

da sind ja einige (gute) Antworten zusammengekommen :)
Vielen Dank dafür, man lernt ja nie aus.

Tatsächlich hat die Funktion "sprintf" knapp 20kB Code geschluckt, also 
schon mal einer der Übeltäter.
Danke für die Erklärung @Yalu X.

Ansonsten, sind die reinen Objectfiles tatsächlich in etwa dem gleichem 
Größen-Rahmen wie die des Realview Compilers.
Mit ein wenig Anpassung hab ich dann auch ca. 17kB 
geschafft(wahrscheinlich gibts da sogar noch mehr Möglichkeit nach oben, 
aber wozu hat man 1MB Flash)

Danke für die schöne Liste @Niklas Gürtler, das hat mir viel 
weitergeholfen.

Uwe B. schrieb:
> das Flash hält 10.000 Schreibzyklen aus
> ich glaube du machst dir da unnötig sorgen

Ich hatte noch die 1000 Zyklen vom STM32F1 in der Wiki im Kopf, aber bei 
10.000 brauch mir tatsächlich keine großen Sorgen machen.

Gruß
Philipp M

von Günter (. (dl4mea)


Lesenswert?

Niklas Gürtler schrieb:
> * Den ARM Compiler mit LTO neu compilen (oder hier
> http://games.2g2s.de/zeug/gcc-arm-none-eabi-4_7-2013q1-20130320-linux.tar.bz2
> von mir ein Binary für Linux loaden) und beim linken deines Programms

Also beim Geocaching und wenn ich ein Premium-Member wäre, dann würde 
ich für das Bereitstellen der Crosstoolchain "einen Favoritenpunkt 
vergeben"

Nur dumm, daß ich auf meinem Linux wegen Gnuradio nur 32bit-Linux 
installiert habe und deine Toolchain für 64bit gebaut ist.

Lass mich dumm fragen: Wie schwer wäre es für dich hier auch eine 
Version für 32Bit zu bauen?

Danke trotzdem!

Günter (dl4mea)

von Stefan (Gast)


Lesenswert?

Aktuelle 32Bit Binaries für Linux/Mac/Win mit LTO+M4F Support gibt es 
von Linaro.

https://launchpad.net/gcc-arm-embedded/4.7

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Günter (dl4mea) schrieb:
> Lass mich dumm fragen: Wie schwer wäre es für dich hier auch eine
> Version für 32Bit zu bauen?
Hm gerade nicht so ganz einfach... Probier vielleicht erstmal den 
Linaro: https://launchpad.net/gcc-linaro

von Günter (. (dl4mea)


Lesenswert?

Hi,

danke erst mal. Hab ich geladen. Aber jetzt mal zwei Fragen:
Bei mir gehts darum Code fürs Beaglebone zu erzeugen. Bislang verwende 
ich die Angstrom-Toolchain unter Eclipse.

Frage 1: Was ist der Unterschied zwischen den zwei gcc, die in den 
Toolchain-Paketen enthalten sind. Zum einen ist ein plain "gcc" und dann 
eins mit Präfix:

/usr/local/gcc-arm-none-eabi-4_7-2013q1$ find . -iname *gcc
./bin/arm-none-eabi-gcc
./arm-none-eabi/bin/gcc

Binär sind beide identisch, wozu also?

Frage 2: Offenbar unterscheiden sich die Pakete immer dadurch, ob sie 
für "Bare Metal" gemacht sind oder ob sie Linux unterstützen. Richtig? 
Fürs Beaglebone brauch ich die Includes und Libs. Kann ich die Libs dann 
einfach vom Bone runterkopieren, und wenn ja, wohin am besten, denn es 
gibt in den Paketen mehrere "passende" Verzeichnisse:

/usr/local/gcc-arm-none-eabi-4_7-2013q1$ find . -name include
./lib/gcc/arm-none-eabi/4.7.3/install-tools/include
./lib/gcc/arm-none-eabi/4.7.3/include
./lib/gcc/arm-none-eabi/4.7.3/plugin/include
./arm-none-eabi/include

/usr/local/gcc-arm-none-eabi-4_7-2013q1$ find . -name lib
./lib
./arm-none-eabi/lib

Oder ist es zwingend nötig die Libs auch mit der crosstoolchain zu 
übersetzen? (Kann mir vorstellen das wäre so mit LTO, aber das jetzt mal 
hinten angestellt)

Danke, Günter

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Günter (dl4mea) schrieb:
> Binär sind beide identisch, wozu also?
Tja weiß ich auch nicht, vielleicht irgendwas historisches mit 
Directory-Layouts...
> Frage 2: Offenbar unterscheiden sich die Pakete immer dadurch, ob sie
> für "Bare Metal" gemacht sind oder ob sie Linux unterstützen. Richtig?
Unter anderem, ja
> Fürs Beaglebone brauch ich die Includes und Libs. Kann ich die Libs dann
> einfach vom Bone runterkopieren, und wenn ja, wohin am besten, denn es
> gibt in den Paketen mehrere "passende" Verzeichnisse:
Du verwendest den Beaglebone mit Betriebssystem (Linux)? Dann bringt dir 
der arm-gcc-embedded (und linaro vermutlich auch) nichts, du brauchst 
einen GCC der für Linux ausführbare ELF's erzeugt. Ich würd die 
libs/includes in ein eigenes Verzeichnis kopieren und CPATH bzw. 
LIBRARY_PATH verwenden um sie für den GCC auffindbar zu machen. Wobei 
die Standard-C & C++ Libraries wie <string.h> oder <vector> ja beim GCC 
dabei sein sollten.

> Oder ist es zwingend nötig die Libs auch mit der crosstoolchain zu
> übersetzen?
Nein, das sollte so gehen. Habe mich aber oben vertan, du musst beim 
compilen jeder C-Datei "-flto" noch mit angeben, damit deren Inhalt mit 
optimiert werden kann.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Kleines Update: Die neue Version vom GCC-ARM-Embedded 
(4.7-2013-q2-update) hat nun LTO eingebaut, und die läuft auch unter 
32bit-x86.

von GCC-Anfänger (Gast)


Lesenswert?

Niklas Gürtler schrieb:
> Kleines Update: Die neue Version vom GCC-ARM-Embedded
> (4.7-2013-q2-update) hat nun LTO eingebaut, und die läuft auch unter
> 32bit-x86.

Die obige Version habe ich geladen und installiert (Windows). Gibt es 
eine einfache Oberfläche, wie z. B. "Programmers Notepad [WinAVR]", in 
der ich den Compiler integrieren kann?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

GCC-Anfänger schrieb:
> Die obige Version habe ich geladen und installiert (Windows). Gibt es
> eine einfache Oberfläche, wie z. B. "Programmers Notepad [WinAVR]", in
> der ich den Compiler integrieren kann?
Jede Oberfläche, die etwas mit dem GCC anfangen kann; eclipse, netbeans, 
Dev-C++, geany, KDevelop, etc. CoIDE ist sogar speziell für die ARM µC 
gemacht. Ich hab mal im Wiki 
http://www.mikrocontroller.net/articles/STM32#GCC aufgelistet was man 
zur direkten Benutzung vom GCC für STM32 braucht.

von GCC-Anfänger (Gast)


Lesenswert?

Danke. Habe die CoIDE gewählt.

von MartinG (Gast)


Lesenswert?

Martin Thomas schrieb:
> stdio
> und insbes. stddio mit FP sind in der newlib zwar universell aber
> speicherhungrig. Es existieren schlankere Implementierungen.

Ich habe aktuell ein recht ähnliches Problem. Der Code wird mit Keil so 
compiliert dass er gut in den Flsh passt bei GCC, trotz Optimierung (-Os 
-flto -ffunction-sections -fdata-sections -Wl,-gc-sections) kommt es zum 
Falsh Overflow (ca. 12kb). Könntest Du die konkreten Libraryalternativen 
(Namen) für stdio+fp benennen. Gibt es für string auch eine reduzierte 
Lib?

von W.S. (Gast)


Lesenswert?

Erstens: Die Optimierungsstufen beim GCC sind m.E. nicht logisch. -O3 
macht meist umfänglicheren und nicht schnelleren Code als -O2 und so 
weiter. Da bleibt nur eines: Ausprobieren.

Zweitens: Warum zum Teufel reitest du auf sowas wie stdio herum? Mach 
dir deine I/O Routinen selber, dann hast du genau DAS, was du brauchst 
und bist wenigstens einigermaßen sicher vor bösen Überraschungen, wenn 
du mal Compiler und/oder µC Architektur wechselst. Ich schreib mein 
Zeugs auch so, daß es auf verschiedensten Zielarchitekturen 
gleichermaßen läuft (bis auf die alleruntersten LowLevel-Routinen) und 
das geht eben nur dann, wenn man auf Kram wie printf und Konsorten 
komplett verzichtet. Sowas ist m.E. auf einem µC ohnehin deplaziert. 
Schließlich weiß man als Programmierer ja wohl, was man wohin ausgeben 
oder hereinholen will.

W.S.

von MartinG (Gast)


Lesenswert?

W.S. schrieb:
> Zweitens: Warum zum Teufel reitest du auf sowas wie stdio herum? Mach
> dir deine I/O Routinen selber, dann hast du genau DAS, was du brauchst
> und bist wenigstens einigermaßen sicher vor bösen Überraschungen, wenn
> du mal Compiler und/oder µC Architektur wechselst.

Das ist genau das Problem, in dem Projekt wird "zwangsweise" fremder 
Code verwendet. Der nutzt leider sscanf sprintf und auch float (in 
Software).

>Ich schreib mein
> Zeugs auch so, daß es auf verschiedensten Zielarchitekturen
> gleichermaßen läuft (bis auf die alleruntersten LowLevel-Routinen)

Wo bekommst Du die Sys-Calls (als Lib) her?

> Sowas ist m.E. auf einem µC ohnehin deplaziert.

Für das Debbugging allerdings sehr hilfreich ohne gleich einen JTAG 
Tracer einzusetzen.

von W.S. (Gast)


Lesenswert?

MartinG schrieb:
> Wo bekommst Du die Sys-Calls (als Lib) her?

Was verstehst du unter Sys-Calls? und dann noch als Lib? Meinst du 
SVC's? oder was dann? Wie ICH sowas mache, kannst du hier in der 
Codesammlung bei der Lernbetty anschauen. Die ist zwar noch ARM7TDMI, 
aber am Prinzip ändert das nix. Standard-IO ist allenfalls auf dem PC 
angesagt, aber doch nicht wirklich nutzvoll auf einem µC.

"Der nutzt leider sscanf sprintf" O je, was hast du denn da an 
greulichem Fremdzeugs? Wenn ich du wäre und die Quellen hätte, würde ich 
mir das Ganze umschreiben. Ich sehe hier in diesem Forum ohnehin viel 
Quellcode-Müll, bei dem alles kreuz und quer voneinander abhängt, lustig 
zwischen allen Moduln hin und hergehupft wird und die Lesbarkeit (und 
damit auch Wartbarkeit) grottenschlecht ist. Aber das gibt's auch 
anderswo, ich erinnere mich an die Quellen zu ANGEL (von ARM), wo es 
ineinander geschachtelte #ifdef Blöcke gab, die sich über mehrere 
Quelldateien hinzog.

Im Zweifelsfall hat man auf lange Sicht mehr davon, wenn man solch einen 
Quellcode-Salat einfach mit der Keule raushaut und das Ganze komplett 
selber (und besser) schreibt. Nebenbei gesagt hatte ich das auch mit der 
Lernbetty so gemacht, weil der damals vorliegende "BOOP"-Code einfach 
nur zu scheußlich war (aber auch weil dessen Autor sich mit seinem 
Copyright seltsam krumm hatte).

W.S.

von Tobias P. (hubertus)


Lesenswert?

@Niklaus Gürtler:

Hmm, kann es sein dass LTO das Programm irgendwie "kaputtoptimiert" ?

Mit LTO:
1
$ arm-none-eabi-size bin/test_rom.elf
2
   text    data     bss     dec     hex filename
3
  48520    3340   24220   76080   12930 bin/test_rom.elf

ohne LTO:
1
$ arm-none-eabi-size bin/test_rom.elf
2
   text    data     bss     dec     hex filename
3
   1192       0       0    1192     4a8 bin/test_rom.elf

es ist zweimal exakt der selbe Code. Das einzige, was ich geändert 
habe, war im Makefile:

CFLAGS += -lto
LDFLAGS += -lto

und dann 'make clean' und 'make'.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Tobias Plüss schrieb:
> Hmm, kann es sein dass LTO das Programm irgendwie "kaputtoptimiert" ?
Funktioniert der Code denn noch?

Aber es ist sehr gut möglich... LTO löscht unbenutzte Funktionen, und 
wenn es die main(), den ISR-Vector oder die ISR's selber als unbenutzt 
erkennt verschwinden die und es bleibt nichts übrig. Daher den 
ISR-Vector mal mit __attribute__((used)) versehen und die davon 
referenzierten ISR's inklusive der indirekt referenzierten main() 
sollten drin bleiben. Schau auch mal in die Disassembly was fehlt.

von Tobias P. (hubertus)


Lesenswert?

Ob es noch funktioniert konnte ich jetzt noch nicht verifizieren, habe 
die HW gerade nicht zur Hand.

Was könnte der Grund sein, dass das selbe Programm mit LTO grösser 
wird?
und zwar signifikant, siehe meinen Auszug von arm-none-eabi-size im 
vorhergehenden Post.

Des Weiteren habe ich jetzt noch ein printf() eingefügt. Also in meiner 
main.c einfach

#include <stdio.h>

und dann in der main():

printf("hello world\n");

mit LTO wird das ganze nicht compiliert. Der Fehler passiert anscheinen 
beim Linken:
1
CC      bin/test_rom.elf
2
`_sbrk_r' referenced in section `.text._malloc_trim_r' of ../lib/gcc/arm-none-eabi/4.8.3/../../../../arm-none-eabi/lib/armv7e-m/fpu/libc.a(l
3
ib_a-freer.o): defined in discarded section `.text' of src/syscalls.c.o (symbol from plugin)
4
`_sbrk_r' referenced in section `.text._malloc_trim_r' of ../lib/gcc/arm-none-eabi/4.8.3/../../../../arm-none-eabi/lib/armv7e-m/fpu/libc.a(l
5
ib_a-freer.o): defined in discarded section `.text' of src/syscalls.c.o (symbol from plugin)
6
`_sbrk_r' referenced in section `.text._malloc_trim_r' of ../lib/gcc/arm-none-eabi/4.8.3/../../../../arm-none-eabi/lib/armv7e-m/fpu/libc.a(l
7
ib_a-freer.o): defined in discarded section `.text' of src/syscalls.c.o (symbol from plugin)
8
`_fstat_r' referenced in section `.text.__smakebuf_r' of ../lib/gcc/arm-none-eabi/4.8.3/../../../../arm-none-eabi/lib/armv7e-m/fpu/libc.a(li
9
b_a-makebuf.o): defined in discarded section `.text' of src/syscalls.c.o (symbol from plugin)
10
`_isatty_r' referenced in section `.text.__smakebuf_r' of ../lib/gcc/arm-none-eabi/4.8.3/../../../../arm-none-eabi/lib/armv7e-m/fpu/libc.a(l
11
ib_a-makebuf.o): defined in discarded section `.text' of src/syscalls.c.o (symbol from plugin)
12
....
Und das füllt mir dann ca. zwei Bildschirmseiten :-)
Der selbe Code, ohne dass ein einziges Bit geändert wird, compiliert, 
wenn ich beim compilieren und Linken das -flto weglasse.

Ob das beim ARM GCC wirklich richtig implementiert ist? Verdächtig ist 
auf jeden Fall, dass das Binary mit LTO grösser wird und teilweise nicht 
mehr compiliert.

Also, es wäre jetzt nicht so, dass ich das unbedingt dringend brauche, 
ich habe kein Platzproblem bei meinem uC. Aber ich wollte LTO halt mal 
ausprobieren, und dabei bin ich eben auf das eben gesagte gestossen :-)

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Tobias Plüss schrieb:
> Was könnte der Grund sein, dass das selbe Programm mit LTO grösser
> wird?
Ohhps es wird größer, hab ich grad überlesen...
> Des Weiteren habe ich jetzt noch ein printf() eingefügt.
> [...]
> Der selbe Code, ohne dass ein einziges Bit geändert wird, compiliert,
> wenn ich beim compilieren und Linken das -flto weglasse.
Das wundert mich jetzt etwas... Hast du denn sbrk, isatty etc. 
implementiert? Wenn nein, was passiert in der Disassembly mit den 
Aufrufen dieser Syscalls von malloc() etc. aus?
>
> Ob das beim ARM GCC wirklich richtig implementiert ist? Verdächtig ist
> auf jeden Fall, dass das Binary mit LTO grösser wird und teilweise nicht
> mehr compiliert.
Ja, und es funktioniert super bei mir :-D Aber ich benutze auch keine 
dynamische Speicherverwaltung mit malloc() und kein OS mit den Syscalls 
sbrk() etc., vielleicht hapert es da etwas mit der libc.

von Tobias P. (hubertus)


Lesenswert?

Hallo,

nein, nein, ich habe weder ein OS noch irgendwelche dyn. Speicher!
Ich habe den Beispielcode

http://www.emb4fun.de/download/arm/examples/STM32F4-Discovery.zip

von hier

http://www.emb4fun.de/arm/examples/index.html

genommen. Als libc wird die vom GCC verwendet. (Da habe ich nichts dran 
gedreht ;-) )

Wie sieht denn dein Beispielcode aus?


In der Disassembly kann ich leider nicht nachschauen, weil ja das ganze 
nicht compiliert werden kann. Er bricht nach den 2 Seiten 
Fehlermeldungen dann ab mit Error 2. (?)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Tobias Plüss schrieb:

> Hmm, kann es sein dass LTO das Programm irgendwie "kaputtoptimiert" ?

> CFLAGS += -lto
> LDFLAGS += -lto

Du willst doch bestimmt auch optimieren, oder nicht? Ohne -O Schalter 
wird nicht optimiert, d.h. es ist wie -O0!

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Tobias Plüss schrieb:
> Hallo,
>
> nein, nein, ich habe weder ein OS noch irgendwelche dyn. Speicher!
> Ich habe den Beispielcode
Du verwendest aber das printf() aus der libc, und das will dynamischen 
Speicher (malloc), und das will ein OS. Wenn du das nicht willst, musst 
du ein alternatives printf() verwenden, das keinen dynamischen Speicher 
braucht.
> Wie sieht denn dein Beispielcode aus?
Was fürn Beispielcode? Mein Code enthält jedenfalls kein printf()
> In der Disassembly kann ich leider nicht nachschauen, weil ja das ganze
> nicht compiliert werden kann.
Ich dachte ohne LTO kompiliert es?

von Tobias P. (hubertus)


Lesenswert?

Ja, Optimierung habe ich wie folgt eingeschaltet:

-Os -O2 -falign-functions=16 -fno-inline -fomit-frame-pointer

Ohne LTO und mit printf() compiliert es.
Ohne LTO und ohne printf() compiliert es sowieso ;-)
Mit LTO und ohne printf() geht es auch.
Mit LTO und mit printf() geht es nicht.

(damit hätten wir wohl alle Varianten erschlagen ;-) )

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Tobias Plüss schrieb:
> -Os -O2 -falign-functions=16 -fno-inline -fomit-frame-pointer
-fno-inline, wozu das denn... Würde mich nicht wundern wenn das in 
Kombination mit LTO komische Dinge bewirkt.
> Ohne LTO und mit printf() compiliert es.
> Ohne LTO und ohne printf() compiliert es sowieso ;-)
> Mit LTO und ohne printf() geht es auch.
> Mit LTO und mit printf() geht es nicht.
Dann zeig doch mal die Disassembly von allen Varianten die 
funktionieren, aber bitte bis auf ein Minimum reduziert, d.h. alles 
rausnehmen bis auf das printf(), oder so.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Tobias Plüss schrieb:
> Ja, Optimierung habe ich wie folgt eingeschaltet:
>
> -Os -O2 -falign-functions=16 -fno-inline -fomit-frame-pointer

Und die werden aucj beim Linken verwendet, ja?  Denn mit LTO ist der 
beim Compilieren erstellte Assembler-Code Makulatur.  Der Compiler wird 
mit den beim LTO-Link angegebenen Optionen erneut aufgerufen.

von Tobias P. (hubertus)


Angehängte Dateien:

Lesenswert?

Hallo Niklas,

hier mal ein Beispiel.

Wenn du es compilierst mit

'make'

dann hagelt es Fehlermeldungen (wegen des -flto).
Dann habe ich aber auch noch mein 'originales' Makefile drin gelassen, 
dort ist -flto nicht drin. Also:

'make -f Makefile_ohne_lto'

und es geht ;-)

und wenn du aus der src/main.c das printf() raus kommentierst, dann 
siehst du auch, dass die angegebenen Grössen der Elf Datei grösser sind, 
wenn mit -flto compiliert und gelinkt wird.


Gruss,Tobias

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Von wegen
Tobias Plüss schrieb:
> nein, nein, ich habe weder ein OS noch irgendwelche dyn. Speicher!
> Ich habe den Beispielcode
In der src/syscalls.c  sind Hilfs-Funktionen für dynamisches 
Speichermanagement definiert, die so tun als wären sie ein OS, damit die 
Standard-libc-Funktion malloc() funktioniert. LTO optimiert die 
scheinbar weg, obwohl sie von der libc gebraucht werden. Einfügen von
1
int _read_r (struct _reent *r, int file, char * ptr, int len) __attribute__((used));
2
int _lseek_r (struct _reent *r, int file, int ptr, int dir) __attribute__((used));
3
int _write_r (struct _reent *r, int file, char * ptr, int len) __attribute__((used));
4
int _close_r (struct _reent *r, int file) __attribute__((used));
5
caddr_t _sbrk_r (struct _reent *r, int incr) __attribute__((used));
6
int _fstat_r (struct _reent *r, int file, struct stat * st) __attribute__((used));
7
int _isatty_r(struct _reent *r, int fd) __attribute__((used));
 am Anfang der Datei weist den GCC an, die Funktionen zu behalten; der 
Code kann dann mit LTO compiliert werden. Allerdings wird er immer noch 
258B größer dadurch. Vermutlich ist dieser Code einfach schlecht zu 
optimieren...

Es sind aber noch stolze 25kB an Code da für ein leeres Programm; 
Memory-Management, "Fake"-OS-Syscalls, "double"-Arithmetik, nur um 
volles printf() zu haben. Sicher dass du so viel Platz dafür hergeben 
willst und nicht doch auf volles printf() verzichten kannst?

von Tobias P. (hubertus)


Lesenswert?

Hi Niklas,
kann ich denn auf das ganze dynamische gedöns verzichten, wenn ich 
printf() weglasse? dann brauche ich auch die syscalls.c nicht. Oder wie 
machst du das bei dir?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Niklas Gürtler schrieb:
> Vermutlich ist dieser Code einfach schlecht zu optimieren...

Das "-Os -O2" optimiert nicht auf Größe, denn -O2 steht hinter -Os und 
überschreibt es daher.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Tobias Plüss schrieb:
> Hi Niklas,
> kann ich denn auf das ganze dynamische gedöns verzichten, wenn ich
> printf() weglasse?
Ja. Oder ein alternatives sparsames printf() verwenden, das z.B. keinen 
double-Support enthält (float ist ja dank FPU effizient).
>dann brauche ich auch die syscalls.c nicht. Oder wie
> machst du das bei dir?
Genau. Ohne printf() brauchts kein malloc(), ohne malloc() kein sbrk 
etc.
Ich hab bis jetzt keine solche String-Verarbeitung gebraucht... Aber dem 
Gefühl nach würde ich Strings fix in .data allokieren und mit itoa etc. 
da hineinschreiben; Code-aufwändiger aber sparsamer.

Johann L. schrieb:
> Das "-Os -O2" optimiert nicht auf Größe, denn -O2 steht hinter -Os und
> überschreibt es daher.
Stimmt... Im makefile stand noch "-O0". "-Os" hat ganze 300 bytes 
gebracht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wenn immer noch ohne -O gelinkt wird ists auch kein Wunder wenn -flto 
nichtmehr bringt im Vergleich zu -O0.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Wenn immer noch ohne -O gelinkt wird ists auch kein Wunder wenn -flto
> nichtmehr bringt im Vergleich zu -O0.
Stimmt, mit -Os linken bringt nochmal ganze 300 bytes. Damit sinds sogar 
weniger als ohne LTO. Woah :o)

von Linda (Gast)


Lesenswert?

@Niklas Gürtler

Du sagst, printf() und Konsorten sollte man nicht verwenden.
Nun, ich habe jetzt hier eine Anwendung, wo ich ein einfaches Terminal 
userinterface realisieren will. Da mein String Output über verschiedene 
Kanäle gehen kann, muss ich zuerst die Strings, die ausgegeben werden 
sollen, fixfertig formatieren, und erst dann ausgeben.

Printf() habe ich daher weggelassen, und ich formatiere jetzt meine 
Strings mit sprintf(). Allerdings wird auch hier ein malloc() eingebaut 
:-) Wie kann ich einen String formatieren, ohne malloc() ?

Also, wie kann ich das
1
sprintf(buffer, "Command entered: %s; return code: %d.\n", my_cmd, ret_val);

einigermassen schön umformulieren?

Um die eigentliche Ausgabe zu ralisiern, habe ich dann eine 
Callbackfunction erstellt, die einen String aufnehmen kann, und die dann 
über einen entsprechenden Kanal den String ausgibt. Der Kanal kann UART 
oder Ethernet sein, durch einfaches Ändern der Callbackfunction kann ich 
so versch. Medien benutzen, aber eben, mit sprintf, und dort hats ein 
malloc() drin... :-(

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Linda schrieb:
> @Niklas Gürtler
>
> Du sagst, printf() und Konsorten sollte man nicht verwenden.
Naja "sollte" ist relativ; man sollte es sich jedenfalls gut überlegen.
> Also, wie kann ich das
1
sprintf(buffer, "Command entered: %s; return code: %d.\n", my_cmd, 
2
ret_val);
>
> einigermassen schön umformulieren?
Naja, was macht das denn? Einen Integer dezimal formatieren und Strings 
zusammenfügen. Ich würde zu sowas tendieren:
1
static Buffer [1024]; // angemessene größe vorher anhand des maximums der Teilstrings berechnen
2
strcpy (Buffer, "Command entered: ");
3
strcpy (Buffer+17, my_cmd);
4
strcpy (Buffer+17+strlen (my_cmd), "; return code: ");
5
itoa (ret_val, Buffer+17+strlen (my_cmd)+15, 10);
6
strcpy (Buffer, ".\n");
Ist wohl ziemlich hässlich. Dafür entfällt der Overhead für das Parsen 
eines Format-Strings. Ich glaube ich programmiere mir mal eine schöne 
C++ Template Library um die Generation solchen Codes zu 
automatisieren...

Du könntest auch eine sprintf Implementation suchen welche ohne malloc() 
auskommt.

von Linda (Gast)


Lesenswert?

Puuuh,
1
static Buffer [1024]; // angemessene größe vorher anhand des maximums der Teilstrings berechnen
2
strcpy (Buffer, "Command entered: ");
3
strcpy (Buffer+17, my_cmd);
4
strcpy (Buffer+17+strlen (my_cmd), "; return code: ");
5
itoa (ret_val, Buffer+17+strlen (my_cmd)+15, 10);
6
strcpy (Buffer, ".\n");

ja sieht ziemlich abenteuerich aus! da gefällt mir mein
1
sprintf(buffer, "Command entered: %s; return code: %d.\n", my_cmd, 
2
ret_val);

schon besser, auch wenns nicht gut ist wegen malloc(). Aber ich glaub, 
ich bau mir da mein sprintf() selber, sofern man nicht unheimlich 
komplexe formatierungen braucht sondern nur paar Strings aneinander 
hängt, geht das ja noch einfach.

Aber wozu braucht printf() oder snprintf() überhaupt malloc() ? auch 
puts() braucht malloc, und das leuchtet mir wirklich nicht ein.

von W.S. (Gast)


Lesenswert?

Linda schrieb:
> Printf() habe ich daher weggelassen, und ich formatiere jetzt meine
> Strings mit sprintf().

Na Klasse, den Teufel mit dem Beelzebub ausgetrieben! Gratulation!


Linda schrieb:
> Da mein String Output über verschiedene
> Kanäle gehen kann, muss ich zuerst die Strings, die ausgegeben werden
> sollen, fixfertig formatieren, und erst dann ausgeben.

> sprintf(buffer, "Command entered: %s; return code: %d.\n", my_cmd, ret_val);


Das mußt du garnicht. Niemand muß sowas. Ich würde das schlichtweg so 
etwa schreiben (benutzte Funktionen siehe Lernbetty):
 word wohin;

 wohin = toUART;
 String_Out("Command entered: ", wohin);
 String_Out(my_cmd, wohin);
 String_Out(" return code: ", wohin);
 Dezi_Out  (ret_val, 1, wohin);
 String_Out(".\r\n", wohin);

Und das wär's. Ohne printf, ohne malloc, ohne strings.h, ohne elenden 
Overhead. OK, String_Out und Dezi_Out beruhen auf Char_Out(char aChar, 
word toWhere) und das muß selber geschrieben werden. aber nen String_Out 
und nen Dezi_Out(long aDez, int mindigits, word toWhere) sollte man ja 
so ziemlich aus dem Ärmel schütteln oder aus der Lernbetty abschreiben 
;-)

Linda, versuche doch endlich mal die geistige Kraft aufzubringen, dich 
von vorgekauten Dingen zu lösen und ein Problem aus eigener Kraft zu 
erledigen.

W.S.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

W.S. schrieb:
> Und das wär's. Ohne printf, ohne malloc, ohne strings.h, ohne elenden
> Overhead. OK, String_Out und Dezi_Out beruhen auf Char_Out(char aChar,
> word toWhere) und das muß selber geschrieben werden.
Und was machen diese Funktionen? Die String-Daten direkt über den 
Ausgabe-Kanal, also UART oder so verschicken? Das will sie aber nicht:

Linda schrieb:
> muss ich zuerst die Strings, die ausgegeben werden
> sollen, fixfertig formatieren, und erst dann ausgeben.

Und so einen String komplett zusammenbauen können deine Funktionen 
nicht. Außerdem kann der Ausgabekanal (zB UART) langsam sein; deine 
Funktionen müssten dann für jedes Zeichen warten bis es weg ist, sodass 
man im Endeffekt viel Zeit mit Warten verschwendet während man auch die 
Formatierung schnell mit einem Puffer hätte abhandeln können und dann 
asynchron senden können.

von Marc P. (marcvonwindscooting)


Lesenswert?

Ich hab vor Jahren den "Ubergang gewagt von Standardzeugs zu einer 
selbergebastelten FIFO-Struktur und mit der mach ich
 - IO, ohne Race-Conditions!
 - Formatierung
 - Parsen

Ja, der FIFO braucht paar Felder, ich verschwende 6 Integer/Pointer = 
24Bytes. Aber damit sind halt soooo viel Probleme ein f"ur allemal 
gel"ost. Und sp"atestens parsen ist ein heftiges Problem f"ur viele in 
dem Thread, wenn schon 'Ausgeben' schwer sein soll.
Ich bin von dem Fifo bis heute nicht mehr weggekommen, im Gegenteil. Bei 
mir bekommen alle wichtigen Strukturen gleich die fifoPrintXXX und 
fifoParseXXX Funktionen, so wie man das bei C++ mit den Operatoren << 
und >> tun w"urde.

Alles was C 'Standard' ist, darf man als Neuling ohne schlechtes 
Gewissen ungesehen in die Tonne treten. Besser man hat so 'nen R*tz im 
Leben nie angefasst.

von W.S. (Gast)


Lesenswert?

Niklas Gürtler schrieb:
> Und was machen diese Funktionen? Die String-Daten direkt über den
> Ausgabe-Kanal, also UART oder so verschicken? Das will sie aber nicht:

Lerne doch erstmal verstehendes Lesen:

Linda schrieb:
> Nun, ich habe jetzt hier eine Anwendung, wo ich ein einfaches Terminal
> userinterface realisieren will. Da mein String Output über verschiedene
> Kanäle gehen kann, muss ich zuerst die Strings, die ausgegeben werden
> sollen, fixfertig formatieren, und erst dann ausgeben.

Also Linda meint, da ihr Stringoutput verschiedene Kanäle bedienen kann, 
müßte man zuvor die Strings komplett aufbauen und erst dann senden. Das 
ist Unsinn oder falsch dargestellt - zumal wenn es sich um ein 
§einfaches Terminal-Useinterface" sprich Kommandozeile handelt.

Deine Frage danach, was die Funktionen machen ist leicht beantwortet: 
Sie machen das, wofür sie da sind, nämlich Texte oder eben Zahlen als 
Texte in den jeweils bezeichneten Ausgabekanal bzw. Stream zu senden. 
Ein Zusammensetzen zu einem Gesamtstring ist dabei völlig unnötig, kann 
aber gemacht werden (toString) falls das wirklich benötigt wird. Du 
hast ungefragt unterstellt, daß es sich bei dem Ausgabekanal immer nur 
um einen UART handelt und das ist falsch. Es kann sich je nach Bedarf um 
einen UART, eine Datei, einen Screenbuffer, einen Drucker oder sonstwas 
handeln, Hauptsache es ist kein ungepuffertes Blockdevice, auf das man 
bekanntlich nur blockweise schreiben kann. Ich habe hier das "toUART" 
nur als relativ übliches Beispiel genommen.

Also erst lesen, dann verstehen, dann erst ans Nörgeln denken.

W.S.

von W.S. (Gast)


Lesenswert?

Marc P. schrieb:
> Ich hab vor Jahren den "Ubergang gewagt von Standardzeugs zu einer
> selbergebastelten FIFO-Struktur und mit der mach ich..

Das ist auch mit Abstand das Beste. Ich benutze bei meinen Projekten für 
so ziemlich alle I/O auch gepufferte Kanäle. Damit sind die Ausgaben 
ruckzuck erledigt, blockieren nur dann, wenn auf größere Datenmengen 
halt gewartet werden MUSS und die eigentliche Transmission erfolgt 
transparent per Interrupts o.ä.

W.S.

von Dr. Sommer (Gast)


Lesenswert?

W.S. schrieb:
> Lerne doch erstmal verstehendes Lesen:
Musst du gerade sagen, der jedem bei jeder Frage sofort dein komisches 
Projekt unter die Nase hälst, das vielleicht als Anti-Beispiel (wie man 
es nicht macht) taugt.

W.S. schrieb:
> Das
> ist Unsinn oder falsch dargestellt - zumal wenn es sich um ein
> §einfaches Terminal-Useinterface" sprich Kommandozeile handelt.
> Ein Zusammensetzen zu einem Gesamtstring ist dabei völlig unnötig
Und was wenn das Programm noch was anderes vorhat als Ewigkeiten auf ein 
langsames UART oder so zu warten?
> kann aber gemacht werden (toString) falls das wirklich benötigt wird.
Und das braucht malloc?

W.S. schrieb:
> Hauptsache es ist kein ungepuffertes Blockdevice,
Tja, schöne Einschränkung. Schön wäre ja eine allgemeingültige Lösung 
Strings zu formatieren, die vom Ziel-Device unabhängig ist?!

W.S. schrieb:
> Also erst lesen, dann verstehen, dann erst ans Nörgeln denken.
Bei dir ist nörgeln nie verkehrt.

W.S. schrieb:
> Ich benutze bei meinen Projekten für
> so ziemlich alle I/O auch gepufferte Kanäle.
Also mit Puffer so wie ich mit itoa etc. geschrieben hatte? Cool.

von W.S. (Gast)


Lesenswert?

OK, herumnörgeln kannst du gut, aber das verstehende Lesen funktioniert 
immer noch nicht.

Weißt du was? Mach doch mal ne Version von der Lernbetty nach deinen 
Vorstellungen. Einfach darum, um hier in diesem Forum mal was 
Produktives beizutragen. Vielleicht ist deine Variante viel grandioser 
als alles zuvor dagewesene. Also mach mal - aber nicht nur mit dem 
Mundwerk.

W.S.

von Dr. Sommer (Gast)


Lesenswert?

W.S. schrieb:
> Weißt du was? Mach doch mal ne Version von der Lernbetty nach deinen
> Vorstellungen. Einfach darum, um hier in diesem Forum mal was
> Produktives beizutragen. Vielleicht ist deine Variante viel grandioser
> als alles zuvor dagewesene. Also mach mal - aber nicht nur mit dem
> Mundwerk.
Sowas in der Art ist in Arbeit, und es ist (wird) hinreichend grandios. 
Dann kannst du dir mal ansehen wie man "echt" wiederverwendbar & sauber 
programmiert.

von Neugieriger Leser (Gast)


Lesenswert?

Und? Ist es schon fertig? ;)

von Dr. Sommer (Gast)


Lesenswert?

Hehe... Hatte keine Lust mehr und andere Projekte sind dazwischen 
gekommen.

von Ludwig (Gast)


Lesenswert?

Dr. Sommer schrieb:

>> Also mach mal - aber nicht nur mit dem Mundwerk.

> Sowas in der Art ist in Arbeit, und es ist (wird) hinreichend grandios.
> Dann kannst du dir mal ansehen wie man "echt" wiederverwendbar & sauber
> programmiert.

Da hat man dich ganz richtig eingeschätzt: Große Klappe, nichts 
dahinter.

von Dr. Sommer (Gast)


Lesenswert?

Es gibt auch Leute die haben noch ein Leben außerhalb von 
mikrocontroller.net. Trollen kann jeder.

von Ludwig (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Es gibt auch Leute die haben noch ein Leben außerhalb von
> mikrocontroller.net. Trollen kann jeder.

Du bist erkannt worden, also nicht ablenken, es geht um deine große 
Klappe. Man lese sich nur deinen Beitrag, der nur so von Überheblichkeit 
strotzt.

von Dr. Sommer (Gast)


Lesenswert?

Ludwig schrieb:
> Man lese sich nur deinen Beitrag, der nur so von Überheblichkeit
> strotzt.
Der ist für W.S., der hat das nötig, wie man leicht erkennt wenn man 
seine penetranten fehlinformierenden predigenden Beiträge im Forum 
sucht. Falls du identisch zu W.S. bist - schön dass dir deine eigene 
Medizin schmeckt.

von W.S. (Gast)


Lesenswert?

Neugieriger Leser schrieb:
> Und? Ist es schon fertig? ;)

rotfl.. natürlich nicht. Wie denn auch?

Du solltest keinerlei konkrete Wirkleistung von diesem Autor erwarten. 
Der Bursche besteht zu 100% aus Scheinleistung.

W.S.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.