Forum: Mikrocontroller und Digitale Elektronik __stdout multiply defined


von Bernhard B. (schluchti)


Lesenswert?

Hi,

ich bin gerade dabei für ein STM32 Derivat Routinen für den USART1 und 
USART2 zu schreiben. Die einzelnen Routinen sollen dann in eigene 
C-Files (usart1.c und usart2.c)  mit zugehörigen Headerfiles ausgelagert 
werden. Jedes C-File für sich kann ich in mein Projekt einbinden und die 
darin enthaltenen Funktionen problemlos aufrufen. Doch wenn ich die 
beiden Dateien gleichzeitig in mein Projekt einbinde, dann bekomme ich 
diese Fehlermeldungen:

USART.axf: Error: L6200E: Symbol __stdout multiply defined (by usart1.o 
and usart2.o).
USART.axf: Error: L6200E: Symbol __stdin multiply defined (by usart1.o 
and usart2.o).

Die beiden C-Files sind folgendermaßen aufgebaut:

.) usart1.c
1
#include "stm32f10x.h"
2
#include <stdio.h>
3
#include "usart1.h"
4
5
struct __FILE { int handle; };
6
FILE __stdout;
7
FILE __stdin;
8
9
#define PUTCHAR_PROTOTYPE_USART1 int fputc(int ch, FILE *f)
10
11
void usart1_init (unsigned long baudrate) {
12
13
[.....]
14
}
15
16
int SendChar (char ch)  {
17
[.....]
18
}
19
20
int GetChar (void)  {
21
[.....]
22
}
23
24
PUTCHAR_PROTOTYPE_USART1
25
{
26
  SendChar((char) ch);
27
  return ch;
28
}


.) usart2.c
1
#include "stm32f10x.h"
2
#include <stdio.h>
3
#include "usart2.h"
4
5
struct __FILE { int handle; };
6
FILE __stdout;
7
FILE __stdin;
8
9
#define PUTCHAR_PROTOTYPE_USART2 int fputc(int ch, FILE *f)
10
11
void usart2_init (unsigned long baudrate) {
12
13
[.....]
14
}
15
16
int SendChar1 (char ch)  {
17
[.....]
18
}
19
20
int GetChar1 (void)  {
21
[.....]
22
}
23
24
PUTCHAR_PROTOTYPE_USART2
25
{
26
  SendChar1((char) ch);
27
  return ch;
28
}

Ich versteh zwar, dass der Fehler durch den struct __FILE Block 
verursacht wird, aber wie kann ich das Problem beseitigen?

Danke!

PS: Ich verwende uVision3 von KEIL

von Klaus W. (mfgkw)


Lesenswert?

Indem z.B. in einer der beiden Dateien abgewandelt wird:
1
extern FILE __stdout;
2
extern FILE __stdin;

von Klaus W. (mfgkw)


Lesenswert?

Ist es eigentlich deine Absicht, erst struct __FILE zu definieren,
und dann aber FILE zu verwenden?
Das sind zwei verschiedene Dinge.

von Bernhard B. (schluchti)


Lesenswert?

Ich muss gestehen, ich hab diesen Block ganz frech aus dem Retarget.c 
File von KEIL geklaut. Ich hab das Schlüsselwort extern jetzt 
hinzugefügt, die beiden Fehler sind verschwunden. Leider hab ich aber 
vorhin eine Fehlermeldung übersehen:
USART.axf: Error: L6200E: Symbol fputc multiply defined (by usart1.o and 
usart2.o).

PS: In einem PDF von ARM hab ich folgendes gefunden:

Symbol __stdout multiply defined (by retarget.o and stdio.o).
This means that there are two conflicting definitions of __stdout 
present – one in
retarget.o, the other in stdio.o. The one in retarget.o is your own 
definition. The
one in stdio.o is the default implementation, which was probably 
linked-in inadvertently.
stdio.o contains a number symbol definitions and implementations of file 
functions like
fopen, fclose, fflush, etc. stdio.o is being linked-in because it 
satisfies some
unresolved references.
To identify why stdio.o is being linked-in, you must link with the 
linker's "verbose" switch,
e.g.:
armlink [... your normal options...] -verbose -errors err.txt
Then study err.txt, so see exactly what the linker is linking-in, from 
where, and why.
To move forward, the user may have to either:
- Eliminate the calls like fopen, fclose, fflush, etc, or
- Re-implement the _sys_xxxx family of functions.

Kann damit jemand etwas anfangen? Ich bin da leider nicht so ganz firm, 
was diese Sachen angeht...

von holger (Gast)


Lesenswert?

>vorhin eine Fehlermeldung übersehen:
>USART.axf: Error: L6200E: Symbol fputc multiply defined (by usart1.o and
>usart2.o).

Dann mach ein fputc1() für USART1 und fputc2() für USART2.
stdout kannst du aber nur für EINEN der beiden USARTS
sinnvoll verwenden.

von Bernhard B. (schluchti)


Lesenswert?

Hab gerade das gefunden: http://www.keil.com/support/docs/2014.htm
Aber jedes Mal vorher das Target auswählen...ich weiß nicht...

von Karl H. (kbuchegg)


Lesenswert?

Bernhard B. schrieb:
> Hab gerade das gefunden: http://www.keil.com/support/docs/2014.htm
> Aber jedes Mal vorher das Target auswählen...ich weiß nicht...

Und wie stellst du dir dann vor dass zb printf wissen soll auf welche 
UART du ausgeben willst?

Du gehst das völlig falsch an.

Die Idee hinter dem Ganzen besteht darin, dass man sich in Analogie zu 
stdout ein zweites Symbol einführt, welches zb für die UART 2 steht.

stdprint würde sich zb anbieten.

Du hast nur eine EINZIGE Funktion fputc (Ich geh mal davon aus, dass das 
Makro PUTCHAR_PROTOTYPE_USART1 bzw PUTCHAR_PROTOTYPE_USART2 diese 
Funktion erzeugt) und diese Funktion verteilt dann das Zeichen je nach 
übergebenem File Argument auf die richtige UART

dann kannst du schreiben

  printf( "Hallo Welt" );
oder
  fprintf( stdout, "Holle Welt" );

und die Ausgabe geht auf UART 1 raus. Schreibst du aber

  fprintf( stdprint, "Hallo Welt" );

dann geht der Text auf der anderen USAR raus.


Es bringt nichts, sich an Internals der Stream Verwaltung und 
Verarbeitung zu vergreifen, wenn man das Prinzip nicht verstanden hat.

Und im übrigen wird eine Weiterleitung über printf IMHO sowieso 
überschätzt. Auf einem µC ist das viel Aufwand für fast nichts.

Viel einfacher ist es, wenn man sich für jedes Gerät eine 
Stringausgabefunktion macht und dann mittels sprintf (oder sonstigen 
Funktionen) und diesen speziellen String Ausgabefunktionen arbeitet.

von Bernhard B. (schluchti)


Lesenswert?

Hallo Karl Heinz,

danke für den ausführlichen Beitrag. Ich glaub, ich weiß auf was du 
hinaus willst. Werd mir mal ein paar Gedanken dazu machen. Sollte ich 
nicht weiterkommen, dann melde ich mich nochmal.

Ansonsten: Danke!

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.