Ich habe festgestellt, dass der aktuelle GCC-ARM ein "\n" am Stringende
wegfrisst! (Ich benutze die CooCox CoIDE, für STM32F4)
Zum Beispiel bei printf("Hallo\n");
Mit einem Hex-Editor kann man im generierten *.bin-File sehen, dass das
\n (=0x10) tatsächlich fehlt.
- Wenn des \n am Stringanfang oder in der Mitte des String steht,
ist es vorhanden.
- Wenn man zwei \n ans Stringende hängt, ist eines vorhanden.
- Ein \r wird nicht weggefressen.
- Optimierungslevel hat keinen Einfluss.
Ich vermute es liegt am Preprozessor: Link => Kapitel 1.1
http://sunsite.ualberta.ca/Documentation/Gnu/gcc-2.95.2/html_chapter/cpp_1.html
Kann es sein, dass der Preprocessor das \n" als Trigraph interpretiert
und aus dem String wegfrisst? Falls "Ja": wie verbiete ich dem
Preprozessor diese Unsitte?
Schau nach, welche Funktion überhaupt aufgerufen wird. Es ist nämlich
gut möglich, dass das 'printf("Hallo\n");' zu einem 'puts("Hallo");'
optimiert wurde.
Peter S. schrieb:> Ich habe festgestellt, dass der aktuelle GCC-ARM ein "\n" am Stringende> wegfrisst!
Ja, nicht nur der für den ARM.
Wenn du statt der Glaskugel einfach den generierten Assemblercode
ansehen würdest, würdest du sofort feststellen, dass er nämlich
das printf() durch ein puts() ersetzt, und dann muss er das
abschließende Newline auch entfernen, denn puts() fügt selbst eins
an.
[edit: Stefan war einen Tick schneller]
Hast du in der CooCox CoIDE die stdio.c ins Projekt eingebunden?
Ich vermute, wie Stefan schon gesagt hat, dass dein \n schon in der
stdio wegoptimiert wird. Bzw. probier es mit \r\n.
>> \n (=0x10)>Soso...
Korrigiere: \n (=(dez)10 = 0x0A)
>Hast du in der CooCox CoIDE die stdio.c ins Projekt eingebunden?
Ja
>Schau nach, welche Funktion überhaupt aufgerufen wird. Es ist nämlich>gut möglich, dass das 'printf("Hallo\n");' zu einem 'puts("Hallo");'>optimiert wurde.
Okey ich gucke mir mal des Assemblercode an.
>> Ich habe festgestellt, dass der aktuelle GCC-ARM ein "\n" am Stringende>> wegfrisst!>Ja, nicht nur der für den ARM.
Und was muss ich tun, damit ich bei printf("Hallo\n"); auch ein \n auf
die UART geschrieben wird wird?
Peter S. schrieb:> Und was muss ich tun, damit ich bei printf("Hallo\n"); auch ein \n auf> die UART geschrieben wird wird?
Ein standardkonformes puts() bereitstellen.
USART_FLAG_TC ist hier der verkehrte Ansatz. Immerhin hat die USART
einen Puffer und den will man üblicherweise nutzen. USART_FLAG_TXE passt
deshalb besser. Und zwar vorher getestet, nicht danach.
Ich würde übrigens dringend davon abraten, in dieser Form die PeriphLib
zu hacken, weil du das in jeder Version neu machen musst und letztlich
über die eigenen Füsse stolperst. Der korrekte Ansatz wäre, PrintChar
auf Basis der unveränderten Lib-Funktionen zu definieren.
Apropos: Wie sieht PrintChar aus?
Hast du denn überhaupt mal kontrolliert, ob das \n in der UART-Ausgabe
tatsächlich fehlt? Denn wie bereits gesagt wurde, dass es am Ende des
Strings im Speicher fehlt hat gar nichts zu sagen. Das \n sollte von
fputs nach dem String automatisch hinzugefügt werden.
>Der korrekte Ansatz wäre, PrintChar>auf Basis der unveränderten Lib-Funktionen zu definieren.
Wie zum Henker geht den das? Ich übe nun seit ca 16 Stunden ein ganz
banales printf für die UART2 auf die Beine zu stellen!!!!
>Hast du denn überhaupt mal kontrolliert, ob das \n in der UART-Ausgabe>tatsächlich fehlt?
Ja, es fehlt definitiv!
>Das \n sollte von fputs nach dem String automatisch hinzugefügt werden.
Ich will aber, dass fputs dann und nur dann ein \n am Stringende
ausgibt, wenn ich auch ein \n am Stringende von printf verwende!
Peter S. schrieb:> Wie zum Henker geht den das?
Sinngemäss:
PrintChar(int c):
if c == LF
PrintChar(CR);
while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
USART_SendChar(c);
Peter S. schrieb:>>Das \n sollte von fputs nach dem String automatisch hinzugefügt werden.> Ich will aber, dass fputs dann und nur dann ein \n am Stringende> ausgibt, wenn ich auch ein \n am Stringende von printf verwende!
Denkst du, die Compilerbauer sind doof, oder was?
Der Compiler ersetzt
printf( String );
natürlich nur dann durch einen Aufruf von puts, wenn der String auch mit
einem \n aufhört.
puts hängt an den String automatisch ein \n an
fputs tut genau das nicht
fputs() darf kein \n am Stringende hinzufügen, nur puts() macht das!
Das ist eine schräge Asymmetrie in der C-Bibliothek, die man nur mit
der Erklärung "historisch gewachsen" belegen kann.
Mit anderen Worten, ein puts() kann man nicht implementieren, indem
man schreibt
1
#define puts(s) fputs(s, stdout)
Wenn das puts() in deiner Bibliothek kein \n von sich aus anhängt,
dann ist es kaputt. => /dev/mülltonne
>Denkst du, die Compilerbauer sind doof, oder was?
Irgendwas muss falsch laufen, wenn ein banales printf so kompliziert
ist, bzw. mir hier offenbar auch keiner ein simples Beispiel geben kann,
wie ich das unter " CooCox CoIDE, für STM32F4" bewerkstelligen kann!
Dachte ich mir. Dort muss die CRLF-Nummer und der TXE-Test rein.
> Irgendwas muss falsch laufen, wenn ein banales printf so kompliziert> ist, bzw. mir hier offenbar auch keiner ein simples Beispiel geben kann,
Nicht jeder verwendet diese Kuh-Hähne und programmieren musst du dein
Programm schon selber. Was du gekriegst hast ist Hilfestellung.
>Wenn das puts() in deiner Bibliothek kein \n von sich aus anhängt,>dann ist es kaputt. => /dev/mülltonne
Ok, die Bibliothek ist nicht von mir , die hat jemand in die IDE
eingefügt! Ich schmeisse sie gerne weg, wenn mir doch bitte jemand
erklären könnte, wie ich eine brauchbare vom aktuellen GCC ARM benutzen
kann!
Wie macht das der Rest von dieser Welt?
Peter S. schrieb:>>Denkst du, die Compilerbauer sind doof, oder was?> Irgendwas muss falsch laufen, wenn ein banales printf so kompliziert> ist,
Ein banales printf ist nicht kompliziert.
Du musst nur der I/O Library dann auch die Treiber-Schicht so zur
Verfügung stellen, wie sie das erwartet. Nicht mehr und nicht weniger.
Mit 'kompliziert' hat das erst mal nicht viel zu tun. Das setzen von
Pixel auf einer VGA-Karte ist auch nicht kompliziert im eigentlichen
Sinne. Aber das ganze mit all den Hilfsfunktionen so in einen Treiber zu
verpacken, dass er Windows als Display-Treiber untergejubelt werden
kann, ist nun mal Aufwand.
Peter S. schrieb:> Wie macht das der Rest von dieser Welt?
Ich verwende gern ein eigenes plattformunabhängiges rprintf mit etwas
reduzierter Funktionalität und dadurch erheblich reduzierter Grösse.
Teils weil unter AVR nichts existierte, teils weil mir die Newlib
mancher ARM-gccs zu monströs war.
Peter S. schrieb:> Wie macht das der Rest von dieser Welt?
Ich würde mal schätzen: Auf diesen ganzen printf/scanf Müll pfeifen.
Ist auf einem µC sowieso viel Aufwand für nichts.
Eine Routine, die einen String ausgeben kann ist schnell geschrieben und
mehr braucht man Low-Level nicht. Maximal das man sich mit sprintf an
die Formatiermöglichkeiten anhängt, die das printf Zeugs mitbringt.
Und für alles was mit Benutzereingabe zu tun hat, ist scanf sowieso
nicht vernünftig zu gebrauchen.
> main.c: printf("\nHallo\n") => puts(const char *pStr)> => pStr @ 0x8002bb4 => "\nHallo\0" (ohne \n)>> printf.c: puts() => fputs(pStr, stdout)
Dann lass doch mal dein puts aus printf.c ansehen!
Dort muss nach dem String noch ein \n ausgegeben werden.
Tut es das nicht, dann hat der, der das geschrieben hat, geschlampt.
Von diesen Funktionen ...
> printf.c: puts() => fputs(pStr, stdout)> printf.c: fputs(const char *pStr, FILE *pStream) => fputc(*pStr,> pStream)> printf.c: fputc(signed int c, FILE *pStream) => PrintChar(c)> printf.c: PrintChar(char c) => USART_SendData(Open_USART, (uint8_t) c);
... sind puts, fputs und fputc Standardfunktionen, die eine genau
vorgeschriebene Funktionalität bereit stellen müssen. Der Compiler
verlässt sich darauf. Tun die Funktionen das nicht, dann geht natürlich
alles weitere schief.
2 The puts function writes the string pointed to by s to the stream
8
pointed to by stdout, and appends a new-line character to the output.
9
The terminating null character is not written.
10
11
Returns
12
3 The puts function returns EOF if a write error occurs; otherwise it
13
returns a nonnegative value.
Es ist nicht definiert, was der Returnwert genau aussagt, ausser das er
in bestimmten Situationen EOF sein soll und wenn die nicht vorliegen,
dann ist der Wert nicht negativ.
>> habe ich nun ersetzt durch...>Was um alles in der Welt machst du da?
Ich wollte einfach die Functioncall-Tiefe nicht weiter aufblähen, daher
habe ich fputs() ge-inlined! ;o)
Peter schrieb:>>Was um alles in der Welt machst du da?> Ich wollte einfach die Functioncall-Tiefe nicht weiter aufblähen, daher> habe ich fputs() ge-inlined! ;o)
Gibts für nicht benutzte Funktionen Geld zurück? ;-)