Forum: Compiler & IDEs ARM-GCC: stderr


von Walter Tarpan (Gast)


Lesenswert?

Hallo zusammen,
beim ARM-GCC gibt es ja keine Streams für stdout und stderr, sondern man 
hängt seine eigene "putchar"-Funktion in stdio.c, die dann von printf & 
Co benutzt wird.

Die Frage ist: Wie bindet man einen Ersatz für stderr ein? Wie kann ich 
eine Ausgabe für assert() und error() festlegen?

Viele Grüße
W.T.

von Klaus W. (mfgkw)


Lesenswert?

Aus 
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gab599ddf60819df4cc993c724a83cb1a4 
(Doku zu fdevopen()):

...
The first stream opened with read intent is assigned to stdin, and the 
first one opened with write intent is assigned to both, stdout and 
stderr.
...

------------------------

Zu assert siehe 
http://www.nongnu.org/avr-libc/user-manual/group__avr__assert.html :

As there is no standard error output stream available for many 
applications using this library, the generation of a printable error 
message is not enabled by default. These messages will only be generated 
if the application defines the macro

 __ASSERT_USE_STDERR

before including the <assert.h> header file. By default, only abort() 
will be called to halt the application.

von Walter Tarpan (Gast)


Lesenswert?

Hallo Klaus,
beim AVR-GCC habe ich das im Griff. Die Frage bezieht sich auf dem 
ARM-GCC.

Viele Grüße
W.T.

von Oliver (Gast)


Lesenswert?

Walter Tarpan schrieb:
> beim ARM-GCC

Klaus Wachtler schrieb:
> Aus
> http://www.nongnu.org/avr-libc/

Falsche Doku, aber richtiger Ansatz: RTFM. Die der Standardlib, die 
verwendet wird.

Oliver

von Walter Tarpan (Gast)


Lesenswert?

Oliver schrieb:
> Falsche Doku, aber richtiger Ansatz: RTFM.

Danke für den Tipp. Und jetzt noch bitte der Link auf die richtige Doku.

von Oliver (Gast)


Lesenswert?

Tja, google...

Welche standardlib die von dir verwendete toolchain verwendet, weiß ja 
hier keiner. ARM-gcc ist da als Angabe nicht ausreichend.

Oliver

von Walter Tarpan (Gast)


Lesenswert?

Oliver schrieb:
> Welche standardlib die von dir verwendete toolchain verwendet, weiß ja
> hier keiner. ARM-gcc ist da als Angabe nicht ausreichend.

Ich ahnte nicht, daß es innerhalb des ARM-GCCs so große Unterschiede 
bezüglich stderr-ähnlichem Vorgehen gibt. Aus der stdio.c konnte ich das 
nicht herauslesen.

Ich verwendet den ARM-GCC 4.7 2013q3 (arm-none-eabi) mit den 
Headerdateien von ST für stm32f10x.

von Karl H. (kbuchegg)


Lesenswert?

Du schreibst immer von der 'stdio.c'

Hast du die in Source Form vorliegen und ist die Bestandteil der glibc? 
Hast du auch den restlichen Code der glibc vorliegen`?
Denn wenn ja: das gibts doch gar nicht, dass man mit den vorliegenden 
Sourcen nicht rausfindet, wie das gedacht ist. So ein Hexenwerk ist das 
I/O Subsystem ja auch wieder nicht.

von Oliver (Gast)


Lesenswert?

Walter Tarpan schrieb:
> Ich ahnte nicht, daß es innerhalb des ARM-GCCs so große Unterschiede
> bezüglich stderr-ähnlichem Vorgehen gibt.

Gibt es auch nicht. ARM-gcc ist der Compiler, der hat mit stderr nichts 
am Hut. Egal, mit welcher toolchain.

stdio.c ist dagegen ein Bestandteil der lib, und welche das ist, sollte 
irgendwo dabei stehen.

Oliver

von Walter Tarpan (Gast)


Angehängte Dateien:

Lesenswert?

Karl Heinz schrieb:
> Du schreibst immer von der 'stdio.c'
>
> Hast du die in Source Form vorliegen und ist die Bestandteil der glibc?
> Hast du auch den restlichen Code der glibc vorliegen`?
> Denn wenn ja: das gibts doch gar nicht, dass man mit den vorliegenden
> Sourcen nicht rausfindet, wie das gedacht ist. So ein Hexenwerk ist das
> I/O Subsystem ja auch wieder nicht.

Hallo Karl-Heinz,
ja, die stdio.c habe ich in Source-Form vorliegen (siehe Anhang) - sie 
wurde von der IDE ins Projektverzeichnis kopiert. Die stdio.h nicht- 
deshalb nehme ich mal an, daß sie unverändert ist.

Den restlichen Quelltext der glibc habe ich noch nicht entdeckt - was 
nicht heißen muß, daß er nicht bei der Installation der Toolchain dabei 
war. Ich werde mal heute Abend Ausschau danach halten. Leider konnte ich 
bislang keine assert.c oder error.c finden, wo sich das Verhalten von 
"stderr" ablesen läßt.

Es mag kein Hexenwerk sein. Nur momentan habe ich noch keine Übersicht, 
nach was ich Ausschau halten sollte. Im Gegensatz zum AVR-GCC, der sich 
ja an den Streams von Standard-C orientiert, scheint beim ARM-GCC ein 
eigenes Süppchen gekocht zu werden. Und mit der wirklich wunderbaren 
Doku beim AVR-GCC kann sich das leider nicht messen. (Und selbst da 
mußte ich damals ein, zwei Fragen im Forum stellen.... ob ich die Doku 
jetzt besser als damals lesen kann, weil ich weiß, was gemeint ist, oder 
ob Jörg die inzwischen noch weiter verbessert hat, weiß ich natürlich 
nicht.)

Viele Grüße
W.T.

von Walter Tarpan (Gast)


Lesenswert?

Walter Tarpan schrieb:
> ja, die stdio.c habe ich in Source-Form vorliegen (siehe Anhang) - sie
> wurde von der IDE ins Projektverzeichnis kopiert.

Hng. Ein Widerspruch direkt im ersten Satz. Meine natürlich: "stdio.c 
habe ich nicht, nur den Ausschnitt, der von der IDE ins 
Projektverzeichnis kopiert wird."

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Walter Tarpan schrieb:
> Ich ahnte nicht, daß es innerhalb des ARM-GCCs so große Unterschiede
> bezüglich stderr-ähnlichem Vorgehen gibt.

Die Standardblibliothek gehört nicht zum GCC. Deswegen nützt es hier 
auch nichts, immer nur die GCC-Version aufzuführen. Du solltest Du 
lieber die Standardblibliothek nennen. Dies kann z.B. die glibc, uClibc, 
newlibc sein.

von Klaus W. (mfgkw)


Lesenswert?

Walter Tarpan schrieb:
> Die Frage bezieht sich auf dem ARM-GCC.

Mist - das kommt davon, wenn man bei A schon aufhört zu lesen :-(

von Karl H. (kbuchegg)


Lesenswert?

Walter Tarpan schrieb:

> Es mag kein Hexenwerk sein. Nur momentan habe ich noch keine Übersicht,
> nach was ich Ausschau halten sollte.


Ich würde mal hier ansetzen
1
signed int fputc(signed int c, FILE *pStream)
2
{
3
    if ((pStream == stdout) || (pStream == stderr)) {
4
5
      PrintChar(c);
6
7
        return c;
8
    }
9
    else {
10
11
        return EOF;
12
    }
13
}

Laut Kommentaren ist fputc der 'untere' Anlaufpunkt für printf und 
Konsorten.
Da steht recht deutlich drinnen, dass die Streams 'stdout' und 'stderr' 
über PrintChar abgehandelt werden.

Hast du denn schon probiert, was passiert, wenn du ein ...
1
#include .... was immer du brauchst ....
2
3
int main()
4
{
5
  fprintf( stdout, "hallo " );
6
  fprintf( stderr, "welt" );
7
8
  fprintf( stdout, "\n" );
9
  fprintf( stderr, "\n" );
10
}

... machst?
Kriegst du Ausgaben?
Notfalls musst du eben entweder in fputc oder in PrintChar eingreifen, 
um die Ausgaben auf ein Gerät deiner Wahl umzuleiten, damit du auch was 
siehst.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Walter Tarpan schrieb:
> Walter Tarpan schrieb:
>> ja, die stdio.c habe ich in Source-Form vorliegen (siehe Anhang) - sie
>> wurde von der IDE ins Projektverzeichnis kopiert.
>
> Hng. Ein Widerspruch direkt im ersten Satz. Meine natürlich: "stdio.c
> habe ich nicht, nur den Ausschnitt, der von der IDE ins
> Projektverzeichnis kopiert wird."

Genau.
Drum heißt die Datei, die du gepostet hast, ja auch printf.c

Oh Mann. Wenn ich für jedes mal raten hier im µC-Forum in den letzten 10 
Jahren 1 Euro bekommen hätte, wäre ich heute ein reicher Mann.

: Bearbeitet durch User
von Walter Tarpan (Gast)


Lesenswert?

Karl Heinz schrieb:
> Ich würde mal hier ansetzen
> signed int fputc(signed int c, FILE *pStream)
> {
>     if ((pStream == stdout) || (pStream == stderr)) {
>
>       PrintChar(c);
>
>         return c;
>     }
>     else {
>
>         return EOF;
>     }
> }
>
> Laut Kommentaren ist fputc der 'untere' Anlaufpunkt für printf und
> Konsorten.
> Da steht recht deutlich drinnen, dass die Streams 'stdout' und 'stderr'
> über PrintChar abgehandelt werden.

Hallo Karl-Heinz,
Du hast Recht. Das sieht extrem vielversprechend aus. Werde ich heute 
abend direkt ausprobieren.

Karl Heinz schrieb:
> Oh Mann. Wenn ich für jedes mal raten hier im µC-Forum in den letzten 10
> Jahren 1 Euro bekommen hätte, wäre ich heute ein reicher Mann.

Dito. Und wenn ich für jedes Mal richtig raten einen Euro bekommen 
hätte, würde es zumindest für eine Pizza reichen :-)

Danke, daß Du Dir die Zeit genommen hast, das durchzusehen! Ich war 
schon so darauf versteift, daß es hier keine Streams und damit "stderr" 
gibt, daß ich nie danach gesucht hätte.

Viele Grüße
W.T.

von Walter T. (nicolas)


Lesenswert?

Hmmm....so einfach scheint das Spiel nicht zu sein.
1
  printf("hallo"); // Geht
2
  fprintf(stdout,"hallo2"); // Build-Fehler

Wenn ich irgendeinen Stream benutze, gibt es einen Linker-Fehler:
1
       [cc] 1 files to be recompiled from dependency analysis.
2
       [cc] 2 total files to be compiled.
3
       [cc] arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -ffunction-sections -g -O3 -std=gnu99 -pedantic -gdwarf-2 -Wextra -c -DSTM32F103V8 -DSTM32F10X_MD -DUSE_STDPERIPH_DRIVER -D__ASSEMBLY__ -DSTM32 -DSTM32F10x -I[...viele Dateien...]
4
       [cc] C:\Users\Nicolas\Desktop\SVN\Funkenerodierer\Firmware_STM32_F103\main.c: In function 'main':
5
       [cc] C:\Users\Nicolas\Desktop\SVN\Funkenerodierer\Firmware_STM32_F103\main.c:83:16: warning: unused variable 's' [-Wunused-variable]
6
       [cc] Starting link
7
       [cc] arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -g -nostartfiles -Wl,-Map=muEDM_F103.map -O3 -Wl,--gc-sections -LC:\STM32_Development\CooCox\CoIDE\configuration\ProgramData\muEDM_F103 -Wl,-TC:\STM32_Development\CooCox\CoIDE\configuration\ProgramData\muEDM_F103/arm-gcc-link.ld -g -o muEDM_F103.elf [...viele Dateien...]
8
       [cc] c:/program files (x86)/gnu tools arm embedded/4.7 2013q3/bin/../lib/gcc/arm-none-eabi/4.7.4/../../../../arm-none-eabi/lib/armv7-m\libg.a(lib_a-impure.o):(.data._impure_ptr+0x0): multiple definition of `_impure_ptr'
9
       [cc] ..\obj\printf.o:printf.c:(.data+0x0): first defined here
10
       [cc] collect2.exe: error: ld returned 1 exit status

Aber das scheint ein Problem der newlib oder der CooCox-Libraries zu 
sein.

von Walter T. (nicolas)


Angehängte Dateien:

Lesenswert?

In printf.c findet sich auch die angemängelten Symbole mit einer 
lapidaren Begründung:
1
/** Required for proper compilation. */
2
struct _reent r = {0, (FILE *) 0, (FILE *) 1, (FILE *) 0};
3
struct _reent *_impure_ptr = &r;

Werden sie auskommentiert, funktioniert der Build. Bei
1
  printf("hallo\a");
2
  fprintf(stdout,"hallo2\a");
3
  printf("hallo3\a");
ist auf dem LCD allerdings nur "hallohallo3" zu sehen (\a ist der alert, 
der dafür sorgt, daß der Inhalt neu gezeichnet wird).

In printf.c läuft allerdings ab "vfprintf" bei "printf" und "fprintf" 
alles gleich ab. Sehr merkwürdig.

Was mich etwas mißtrauisch macht, ist daß beim Verwenden von "fprintf" 
plötzlich etwas anderes gelinkt wird. Die Link-Optionen habe ich 
allerdings mich noch nie anzufassen getraut...

[EDIT:]

Sieh an, es gibt schon eine Application Note zu dem Thema. Jetzt müßte 
man nur noch chinesisch können:

http://www.coocox.org/forum/topic.php?id=3740

Aber ich denke es ist einfacher, die printf.c zu reparieren.


[EDIT2:]

Es wird immer mysteriöser. Lasse ich die Stream-Auswahl heraus, also
1
signed int fputc(signed int c, FILE *pStream)
2
{
3
    //if ((pStream == stdout) || (pStream == stderr)) {
4
  if (1) {
5
      PrintChar(c);
6
        //PrintChar(c);
7
8
        return c;
9
    }
10
    else {
11
12
        return EOF;
13
    }
14
}
ändert sich nichts am Verhalten. Es wird aber definitiv diese Funktion 
aufgerufen, denn wird PrintChar doppelt aufgerufen, ist auch alles 
doppelt auf dem Display.

Also irgendetwas muß in der Kette
fprintf -> vfprintf -> fputs -> fputc -> PrintChar kaputt sein, was in
printf -> vprintf -> vfprintf -> fputs -> fputc -> PrintChar 
funktioniert.

[EDIT 3]: WTF??? Der Debugger sagt mir, daß in fprintf gar nicht 
eingesprungen wird.

[EDIT 4]: Eine Endlosschleife in fprintf bestätigt diese Vermutung.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Tja. Die Stunde ist abgelaufen. Ich kann nicht mehr editieren. Und 
bleibe verwirrt. Was mag den Linker dazu bewegen, einen Funktionsaufruf 
zu entfernen? Oder existiert irgendwo eine Funktion mit demselben Namen 
und stärkerer Bindung?

von mar IO (Gast)


Lesenswert?

Das könnte dich interessieren

http://embdev.net/topic/133927#1218465

von Walter T. (nicolas)


Angehängte Dateien:

Lesenswert?

mar IO schrieb:
> Das könnte dich interessieren
>
> http://embdev.net/topic/133927#1218465

Das ist interessant... aber ich nehme an, daß die Stubs schon in 
syscalls.c richtig implementiert sind. Ich bekomme ja schon Output.

Ich habe printf dahingehend modifiziert, daß es fprintf benutzt (siehe 
Anhang). In main mache ich:
1
  printf("hallo1 \a");
2
  fprintf(stdout,"hallo2 \a");
3
  printf("hallo3 \a");
4
5
  while(1);
und die Ausgabe ist "hallo1 hallo3".

Es sieht aus, als sähe main ein anderes fprintf als printf.c. Wie geht 
soetwas?
So langsam befürchte ich, daß das hier meine Fähigkeiten übersteigt.

Ich muß heute abend mal ein lauffähiges Minimalbeispiel erzeugen.

von M. K. (avr-frickler) Benutzerseite


Angehängte Dateien:

Lesenswert?

Schau doch mal ob du bei den Link-Optionen die "newlib" oder ähnliches 
auswählen kannst.

von Haro (Gast)


Lesenswert?

Walter Tarpan schrieb:
> Was mag den Linker dazu bewegen, einen Funktionsaufruf
> zu entfernen? Oder existiert irgendwo eine Funktion mit demselben Namen
> und stärkerer Bindung?

Zumindest avr-gcc kann bei printf sehr aggresiv optimieren.
Ein
1
printf("Hallo");
 führt bspw. dazu, dass kein dickes printf dazugelinkt wird sondern ein 
puts(), weil dieses auch einen konstanten String ausgeben kann.
Wird wirklich ein printf benötigt stehen dem Compiler soweit ich weiß 
mehrere Versionen zur Verfügung, abhängig vom nötigen Funktionsumfang.

Möglicherweise solltest du die Optimierung abschalten, oder dem Compiler 
die Möglichkeit zur Optimierung nehmen, z.B. indem du einen printf 
Aufruf in eine globale Funktion kapselst, die von extern aufgerufen 
werden kann.

von Walter Tarpan (Gast)


Lesenswert?

Haro schrieb:
> Zumindest avr-gcc kann bei printf sehr aggresiv optimieren.

Hallo Haro,
ich weiß nicht, ob das gerade verwechselt wurde, aber ich schreibe es 
lieber noch einmal groß auf:

Kein AVR! ARM *ARM* ARM *ARM* ARM *ARM* ARM

;-)

Das war es mir schon allein wegen der interessanten Formatierung wert.

In printf kann mit dem Debugger gesprungen werden - also ist es auch 
vorhanden. fprintf fehlt.

von Rolf Magnus (Gast)


Lesenswert?

Haro schrieb:
> Zumindest avr-gcc kann bei printf sehr aggresiv optimieren.

Das gibt's nicht nur auf dem AVR. Kann also gut sein, daß der 
fprintf()-Aufruf durch einen direkten Aufruf von fputs() oder so ersetzt 
wurde. Am besten mal in den generierten Assembler-Code schauen, was 
tatsächlich passiert.

von Rolf Magnus (Gast)


Lesenswert?

Walter Tarpan schrieb:
> Haro schrieb:
>> Zumindest avr-gcc

> Kein AVR! ARM ARM ARM ARM ARM ARM ARM

Du weißt aber schon, was das Wörtchen "zumindest" hier ausdrücken soll?

von Walter Tarpan (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Du weißt aber schon, was das Wörtchen "zumindest" hier ausdrücken soll?

Hmm....die Zitat-Formatierung ist noch interessanter. Ja, ich weiß, was 
damit gemeint ist. Allerdings will ich verhüten, daß die Diskussion 
Richtung AVR abdriftet.

von Haro (Gast)


Lesenswert?

Walter Tarpan schrieb:
> Ja, ich weiß, was
> damit gemeint ist. Allerdings will ich verhüten, daß die Diskussion
> Richtung AVR abdriftet.

Genau dafür war mein "zumindest" gedacht. Denn der Folgegedanke meiner 
Aussage ist ja: möglicherweise arbeitet der gcc-arm-none-eabi oder was 
immer Coocox benutzt ähnlich.

Aber Diskussionen driften hier schnell ab, da hast du leider recht.

Wie auch immer, wenn du Debuggen kannst ist die Funktion drinnen. Im 
Zweifel das Map-File konsultieren, dem traue ich da immer mehr.
Aber wie gesagt, schalt doch mal die Optimierung ab.

Auch wenn ich mich jetzt wieder auf dünnes Eis begebe: du weißt ja 
anscheinend, wie man in der avr-libc printf auf eine eigene 
Ausgabemethode umleitet (Stichwort stdout umleiten, gibts hier ja 
irgendwo ein Tut).

Wenn es bei deiner Toolchain kein stderr gibt könntest du dir diesen 
Stream ja selber anlegen, mit einem Funktionszeiger auf deine gewünschte 
putc-Funktion. Ein eigenes error() zu schreiben ist dann trivial: dein 
error() kapselt nur einen fprintf-Aufruf auf dein zuvor erstelltes 
stderr.

Nachteil: du arbeitest an der Toolchain vorbei und kochst dein eigenes 
Süppchen
Allerdings kann man den Mechanismus ja in die plattform-spezifischen 
Header legen, dann kompiliert der gleiche Code unter ARM und AVR, bei 
letzterem läuft die Ausgabe über die avr-libc.

von Walter T. (nicolas)


Lesenswert?

M. K. schrieb:
> Schau doch mal ob du bei den Link-Optionen die "newlib" oder ähnliches
> auswählen kannst.

Haro schrieb:
> Möglicherweise solltest du die Optimierung abschalten,

Ich habe jetzt mal folgende Optionen ausprobiert:
 - Not use C Library
 - Use nano C Library
 - Use base C Library
 - Semihosting
 - Retarget.

Außerdem die Optimierung auf O0 geschaltet.

Das Ergebnis ist immer dasselbe. (Selbstverständlich habe ich bei jedem 
Build einen String geändert, um sicherzustellen, daß keine alten 
Darstellungen übrigbleiben).

Es bleibt mysteriös.

[EDIT:] Ich werde (oder bin bereits) bekloppt. So wird alles 
dargestellt:
1
  printf("hallo1 \a");
2
  fprintf(stdout,"hallo2 %i \a",s);
3
  printf("hallo8 \a");
4
  fprintf(stdout,"hallo4 %i\a",4);
(s ist ein uint_fast8_t und Rückgabewert einer Funktion). Dabei war mein 
Minimalbespiel gerade fast fertig...

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Hmmm....aus der folgenden Main:
1
  printf("hallo1 \n\a");
2
  fprintf(stdout,"hallo2 %i \n\a",s);
3
  fprintf(stdout,"hallo3 \n\a");
4
  printf("hallo4 \n\a");
5
  fprintf(stdout,"hallo5 %i\n\a",4);
wird folgende lss:
1
  setbuf(stdin, NULL);
2
 8001500:  f240 4348   movw  r3, #1096  ; 0x448
3
 8001504:  f2c2 0300   movt  r3, #8192  ; 0x2000
4
 8001508:  681b        ldr  r3, [r3, #0]
5
 800150a:  685b        ldr  r3, [r3, #4]
6
 800150c:  4618        mov  r0, r3
7
 800150e:  f04f 0100   mov.w  r1, #0
8
 8001512:  f001 fb31   bl  8002b78 <setbuf>
9
  setbuf(stdout, NULL);
10
 8001516:  f240 4348   movw  r3, #1096  ; 0x448
11
 800151a:  f2c2 0300   movt  r3, #8192  ; 0x2000
12
 800151e:  681b        ldr  r3, [r3, #0]
13
 8001520:  689b        ldr  r3, [r3, #8]
14
 8001522:  4618        mov  r0, r3
15
 8001524:  f04f 0100   mov.w  r1, #0
16
 8001528:  f001 fb26   bl  8002b78 <setbuf>
17
18
  printf("hallo1 \n\a");
19
 800152c:  f245 6080   movw  r0, #22144  ; 0x5680
20
 8001530:  f6c0 0000   movt  r0, #2048  ; 0x800
21
 8001534:  f000 fdd6   bl  80020e4 <printf>
22
  fprintf(stdout,"hallo2 %i \n\a",s);
23
 8001538:  f240 4348   movw  r3, #1096  ; 0x448
24
 800153c:  f2c2 0300   movt  r3, #8192  ; 0x2000
25
 8001540:  681b        ldr  r3, [r3, #0]
26
 8001542:  689a        ldr  r2, [r3, #8]
27
 8001544:  89fb        ldrh  r3, [r7, #14]
28
 8001546:  4610        mov  r0, r2
29
 8001548:  f245 618c   movw  r1, #22156  ; 0x568c
30
 800154c:  f6c0 0100   movt  r1, #2048  ; 0x800
31
 8001550:  461a        mov  r2, r3
32
 8001552:  f000 fdaf   bl  80020b4 <fprintf>
33
  fprintf(stdout,"hallo3 \n\a");
34
 8001556:  f240 4348   movw  r3, #1096  ; 0x448
35
 800155a:  f2c2 0300   movt  r3, #8192  ; 0x2000
36
 800155e:  681b        ldr  r3, [r3, #0]
37
 8001560:  689b        ldr  r3, [r3, #8]
38
 8001562:  f245 609c   movw  r0, #22172  ; 0x569c
39
 8001566:  f6c0 0000   movt  r0, #2048  ; 0x800
40
 800156a:  f04f 0101   mov.w  r1, #1
41
 800156e:  f04f 0209   mov.w  r2, #9
42
 8001572:  f001 faed   bl  8002b50 <fwrite>
43
  printf("hallo4 \n\a");
44
 8001576:  f245 60a8   movw  r0, #22184  ; 0x56a8
45
 800157a:  f6c0 0000   movt  r0, #2048  ; 0x800
46
 800157e:  f000 fdb1   bl  80020e4 <printf>
47
  fprintf(stdout,"hallo5 %i\n\a",4);
48
 8001582:  f240 4348   movw  r3, #1096  ; 0x448
49
 8001586:  f2c2 0300   movt  r3, #8192  ; 0x2000
50
 800158a:  681b        ldr  r3, [r3, #0]
51
 800158c:  689b        ldr  r3, [r3, #8]
52
 800158e:  4618        mov  r0, r3
53
 8001590:  f245 61b4   movw  r1, #22196  ; 0x56b4
54
 8001594:  f6c0 0100   movt  r1, #2048  ; 0x800
55
 8001598:  f04f 0204   mov.w  r2, #4
56
 800159c:  f000 fd8a   bl  80020b4 <fprintf>
57
58
  while(1);
59
 80015a0:  e7fe        b.n  80015a0 <main+0x148>
60
 80015a2:  bf00        nop
61
62
080015a4 <SysTick_Handler>:
63
}
Das heißt bei fprintf mit konstantem String wird in fwrite und nicht in 
fprintf gesprungen. Und fwrite ist in printf.c gar nicht definiert. 
fwrite liegt in libg.a.

Ob mir dieses Wissen irgendwie hilft?

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Und wenn ich meine eigene Implementierung von fwrite in printf.c 
hinterlege, geht alles.

Danke für die Geduld und für's Lesen!

Viele Grüße
W.T.

von Walter T. (nicolas)


Lesenswert?

Vor zweieinhalb Stunden dachte ich, ich hätte es verstanden. Aber in 
Wirklichkeit ist es mir rätselhaft:

Wie schafft es der Build-Prozeß, aus einem Funktionsaufruf (fprintf) 
einen Funktionsaufruf einer komplett anderen Funktion (fwrite) zu 
machen, die nichts miteinander zu tun haben? fwrite kommt in der 
Aufruf-Kette von fprintf nirgendwo vor, und die Signatur ist ja auch 
komplett anders. Und es kommt ja auch etwas Anderes heraus (fprintf ruft 
letztendlich PrintChar auf, fwrite nicht)?

[EDIT:} OK, hier:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=9967

gibt es einen Bug-Report, daß dieser Verhalten manchmal unerwünscht ist. 
Aber wie kommt es überhaupt dazu?

: Bearbeitet durch User
von Rolf Magnus (Gast)


Lesenswert?

Walter Tarpan schrieb:
> Aber wie kommt es überhaupt dazu?

Naja, normalerweise gehen fprintf und fwrite ja ans selbe Ziel, nämlich 
den angegebenen Stream. Wie schon erwähnt, optimiert der Compiler den 
fprintf-Aufruf zu was einfacherem, wenn kein Formatstring geparst werden 
muß.

Walter Tarpan schrieb:
> Und es kommt ja auch etwas Anderes heraus (fprintf ruft letztendlich
> PrintChar auf, fwrite nicht)?

Das ist aber spezifisch für die von dir verwendete Libc. Der Compiler 
weiß von dieser Sonderbehandlung halt nix.

von Walter Tarpan (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Wie schon erwähnt, optimiert der Compiler den
> fprintf-Aufruf zu was einfacherem, wenn kein Formatstring geparst werden
> muß.

Also ist davon auszugehen, daß irgendwo im Compiler eine Tabelle ist, wo 
hart verdrahtet ist:
fprintf(<file>,<konstanter String>) ->
fwrite(<konstanter String>,<strlen(<konstanter String>-1,1,<file>) ?

von Walter Tarpan (Gast)


Lesenswert?

)

Nur für den Fall, daß die fehlende Klammer sonst dem Leser den Tag 
vermiest...

von Rolf Magnus (Gast)


Lesenswert?

Walter Tarpan schrieb:
> Rolf Magnus schrieb:
>> Wie schon erwähnt, optimiert der Compiler den
>> fprintf-Aufruf zu was einfacherem, wenn kein Formatstring geparst werden
>> muß.
>
> Also ist davon auszugehen, daß irgendwo im Compiler eine Tabelle ist, wo
> hart verdrahtet ist:
> fprintf(<file>,<konstanter String>) ->
> fwrite(<konstanter String>,<strlen(<konstanter String>-1,1,<file>) ?

Da steckt schon noch etwas mehr dahinter als eine simple Tabelle. 
fprintf ist eineim  Compiler eingebaute Funktion, die versucht, so viel 
wie möglich von der Rechenarbeit auf die Compilezeit zu verlagern und 
das fprintf der Laufzeitbibliothek nur dann aufzurufen, wenn's kein 
Optimierungspotenzial gibt. Abschalten kannst du dieses Verhalten mit 
-fno-builtin-fprintf. Das gilt letztendlich für einen sehr großen Teil 
der Standardfunktionen. memcpy() kann z.B. auch auf ganz 
unterschiedliche Arten umgsetzt werden, je nachdem, welche Argumente man 
übergibt. Da wird nicht immer eine Funktion aufgerufen, die in einer 
Schleife Byte für Byte kopiert. Siehe die Liste der built-in-Funktionen 
hier:
http://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Other-Builtins.html#Other-Builtins

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.