mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik __stdout multiply defined


Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht 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
#include "stm32f10x.h"
#include <stdio.h>
#include "usart1.h"

struct __FILE { int handle; };
FILE __stdout;
FILE __stdin;

#define PUTCHAR_PROTOTYPE_USART1 int fputc(int ch, FILE *f)

void usart1_init (unsigned long baudrate) {

[.....]
}

int SendChar (char ch)  {
[.....]
}

int GetChar (void)  {
[.....]
}

PUTCHAR_PROTOTYPE_USART1
{
  SendChar((char) ch);
  return ch;
}


.) usart2.c
#include "stm32f10x.h"
#include <stdio.h>
#include "usart2.h"

struct __FILE { int handle; };
FILE __stdout;
FILE __stdin;

#define PUTCHAR_PROTOTYPE_USART2 int fputc(int ch, FILE *f)

void usart2_init (unsigned long baudrate) {

[.....]
}

int SendChar1 (char ch)  {
[.....]
}

int GetChar1 (void)  {
[.....]
}

PUTCHAR_PROTOTYPE_USART2
{
  SendChar1((char) ch);
  return ch;
}

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

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Indem z.B. in einer der beiden Dateien abgewandelt wird:
extern FILE __stdout;
extern FILE __stdin;

Autor: Klaus Wachtler (mfgkw)
Datum:

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

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Bernhard B. (schluchti)
Datum:

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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Bernhard B. (schluchti)
Datum:

Bewertung
0 lesenswert
nicht 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!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.