Forum: Mikrocontroller und Digitale Elektronik Fehler bei inline Anweisung


von Andre H. (andre01)


Lesenswert?

Hallo zusammen,
ich habe mal ne Frage zu einer Compilerfehlermeldung. Ich versuche 
gerade den Datenrekorder aus der Codesammlung zu verwirklichen. 
Komischerweise bekomme ich beim Compilieren diese Fehlermeldung...
Ich kann mit der nicht viel anfangen
1
> "make.exe" all
2
3
-------- begin --------
4
avr-gcc (WinAVR 20090313) 4.3.2
5
Copyright (C) 2008 Free Software Foundation, Inc.
6
This is free software; see the source for copying conditions.  There is NO
7
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8
9
10
Compiling C: ../../Logger/MrData/spi.c
11
avr-gcc -c -mmcu=atmega8 -I. -gdwarf-2 -DF_CPU=3686400UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=./../../Logger/MrData/spi.lst  -std=gnu99 -Wundef -MMD -MP -MF .dep/spi.o.d ../../Logger/MrData/spi.c -o ../../Logger/MrData/spi.o 
12
13
Linking: main.elf
14
avr-gcc -mmcu=atmega8 -I. -gdwarf-2 -DF_CPU=3686400UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=main.o  -std=gnu99 -Wundef -MMD -MP -MF .dep/main.elf.d main.o ../../Logger/MrData/delay.o ../../Logger/MrData/fat16.o ../../Logger/MrData/mmc.o ../../Logger/MrData/spi.o --output main.elf -Wl,-Map=main.map,--cref     -lm
15
../../Logger/MrData/mmc.o: In function `MMC_cleanup':
16
D:\AVR\Logger\MrData/../../Logger/MrData/mmc.c:190: undefined reference to `spi_io'
17
D:\AVR\Logger\MrData/../../Logger/MrData/mmc.c:191: undefined reference to `spi_io'
18
../../Logger/MrData/mmc.o: In function `MMC_get_sec_stop_w':
19
D:\AVR\Logger\MrData/../../Logger/MrData/mmc.c:407: undefined reference to `spi_io'
20
D:\AVR\Logger\MrData/../../Logger/MrData/mmc.c:408: undefined reference to `spi_io'
21
D:\AVR\Logger\MrData/../../Logger/MrData/mmc.c:410: undefined reference to `spi_io'
22
../../Logger/MrData/mmc.o:D:\AVR\Logger\MrData/../../Logger/MrData/mmc.c:381: more undefined references to `spi_io' follow
23
make.exe: *** [main.elf] Error 1

Der Code den der Compiler nicht mag :
1
 inline u08 spi_io(u08 data){
2
/*  UDR0 = data;
3
  while (!(UCSR0A&(1<<RXC0)));
4
  return UDR0;*/
5
  outp(data, SPDR);
6
  while((inp(SPSR)&(1<<SPIF)) == 0x00){};
7
  return inp(SPDR);

Ich habe an dem Projekt nichts geändert.
Vielleicht weiß ja jemand was mein Compiler daran nicht mag...


Gruß
André

von Lasse S. (cowz) Benutzerseite


Lesenswert?

Hast du die Funktion denn vorher deklariert?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Deklariert ist die Funktion, da sonst der Compiler motzen würde. Wer 
hier motzt, ist der Linker.
Und das lässt vermuten, daß es eine Deklaration in Form eines 
Funktionsprototypen gibt, die nicht darauf hinweist, daß das eine 
inline-Funktion sein soll.

von Karl H. (kbuchegg)


Lesenswert?

Ich würde ich auch ein static Problem nicht ausschliessen.

Gut wäre natürlich gewesen, wenn der TO ganz einfach einen Link zum 
Projekt in der Codesammlung gesetzt hätte. Dann hätte man sich den Code 
ansehen können.

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


Lesenswert?

Andre H. schrieb:
> Der Code den der Compiler nicht mag :

Da gibt es nirgends eine Compilermeldung, die besagt, dass er daran
was auszusetzen hätte.

Was es dafür gibt ist eine *Linker*meldung.  Der findet die nämlich
nicht.  Wie auch?  Wenn sie "inline" sein soll, muss der Compiler
sie bereits auflösen können, nicht erst der Linker -- der kann sowas
nicht mehr nachträglich in den Code reinbasteln.

Damit der Compiler sie aber überall gleichermaßen kennt und auch in
den Code einfügen kann, gibt es für inline-Funktionen eine Ausnahme
von der "goldenen" Regel, nach der man keine Implementierungen direkt
in Headerdateien schreibt: inline sollte man, damit es Sinn hat,
in der Headerdatei implementieren.  Damit man nicht später noch über
andere Kasperfallen stolpert, bitte gleich und immer "static inline".

von Andre H. (andre01)


Angehängte Dateien:

Lesenswert?

Hallo,
danke schon mal für die Antworten...

@ Karl heinz Buchegger
stimmt habe ich versäumt hier der Link zu dem Projekt..
[Beitrag "Datenrekorder auf SD-Karte mit mega88"]
und die Zip Datei auch mal mit angefügt bei der mir das passiert...

Das mit dem static vor dem inline habe ich schon mal getestet da es hier 
in Forum in einem andren Beitrag angeführt wurde, aber es gab immer noch 
die Meckerei.

Gruß André

von Karl H. (kbuchegg)


Lesenswert?

lol

Schmeiss das inline bei der Funktion im spi.c raus.
Das ist sowieso sinnlos dort.

Da hat jemand nicht verstanden was inline macht und wie es funktioniert.

Obwohl: Zu einem Fehler dürfte es trotzdem nicht kommen. Solange die 
Funktion nicht static ist, muss der Compiler einen Funktionsrumpf 
erzeugen, selbst wenn die Funktion als inline markiert ist. Eventuelle 
Compilerschalter könnten das noch überschreiben, aber die hab ich jetzt 
nicht mehr geprüft.

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


Lesenswert?

Karl heinz Buchegger schrieb:
> Obwohl: Zu einem Fehler dürfte es trotzdem nicht kommen.

Doch.  C99 hat die Semantik von inline etwas anders definiert, als
GCC sie historisch implementiert hat.  Eine "extern inline"-Funktion
muss in C99 zwingend auch noch eine Implementierung ohne "inline"
liefern, denn es ist dem Compiler dann freigestellt, ob er die
Funktion inline erweitert oder ob er die extern implementierte
Funktion ruft.

Andre H. schrieb:
> Das mit dem static vor dem inline habe ich schon mal getestet da es hier
> in Forum in einem andren Beitrag angeführt wurde, aber es gab immer noch
> die Meckerei.

Klar, weil du noch gar nicht verstanden hast, wie der Compiler eine
inline-Funktion implementieren muss, damit sie Sinn hat: er muss
den Code an jeder Stelle, an der die Funktion "gerufen" wird, auch
besitzen.

Kurzfassung nochmal: "inline"-Funktionen, die in mehr als einer
Quelldatei benutzt werden sollen, gehören nicht in eine .c-Datei,
sondern in eine .h-Datei.  "inline" sollte man immer als "static
inline" schreiben (sofern man nicht ganz genau verstanden hat, wie
C99 mit "extern inline" umgeht, und dieses Verhalten explizit
wünscht).

von Karl H. (kbuchegg)


Lesenswert?

Jörg Wunsch schrieb:
> Karl heinz Buchegger schrieb:
>> Obwohl: Zu einem Fehler dürfte es trotzdem nicht kommen.
>
> Doch.  C99 hat die Semantik von inline etwas anders definiert, als
> GCC sie historisch implementiert hat.  Eine "extern inline"-Funktion
> muss in C99 zwingend auch noch eine Implementierung ohne "inline"
> liefern, denn es ist dem Compiler dann freigestellt, ob er die
> Funktion inline erweitert oder ob er die extern implementierte
> Funktion ruft.

Versteh ich da etwas falsch.
Es war doch auch bisher so, dass eine inline Funktion eine 
Implementierung haben musste. Es sei denn sie ist static inline, weil 
nur dann sicher gestellt ist, dass die Funktion von nirgendwo anders 
aufgerufen werden kann.

von Andre H. (andre01)


Lesenswert?

Karl heinz Buchegger schrieb:
> Schmeiss das inline bei der Funktion im spi.c raus.
> Das ist sowieso sinnlos dort.

Wie meinst denn das jetzt? Ersatzlos streichen geht ja nicht ist ja in 
anderen Dateien in Verwendung...

Naja ich habe das ja nicht programmiert...
Aber wenn ich die inline Anweisung richtig verstehe, wird der Code 
direkt an der Stelle erzeugt und eingefügt wo er so zusagen aufgerufen 
wird.
( so tief in c stecke ich noch nicht drin aber es wird besser )

Die Frage liegt das nun an dem Makefile was ich selbst gemacht habe oder 
an der spi.c/.h?

Achja,
im Betrag zu dem Projekt wird erwähnt das das mit WinAVR compiliert 
wurde (2008), deshalb wundere ich mich das es bei mir nicht klappt...


Gruß André

von Karl H. (kbuchegg)


Lesenswert?

Andre H. schrieb:
> Karl heinz Buchegger schrieb:
>> Schmeiss das inline bei der Funktion im spi.c raus.
>> Das ist sowieso sinnlos dort.
>
> Wie meinst denn das jetzt? Ersatzlos streichen geht ja nicht ist ja in
> anderen Dateien in Verwendung...

Einfach das Schlüsselwort inline ersatzlos streichen.
1
08 spi_io(u08 data){
2
/*  UDR0 = data;
3
  while (!(UCSR0A&(1<<RXC0)));
4
  return UDR0;*/
5
  outp(data, SPDR);
6
  while((inp(SPSR)&(1<<SPIF)) == 0x00){};
7
  return inp(SPDR);
8
}

> Aber wenn ich die inline Anweisung richtig verstehe, wird der Code
> direkt an der Stelle erzeugt und eingefügt wo er so zusagen aufgerufen
> wird.
> ( so tief in c stecke ich noch nicht drin aber es wird besser )

Und wie soll der Compiler das machen, wenn er den Funktionskörper an der 
Aufrufstelle nie zu Gesicht bekommt?

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


Lesenswert?

Karl heinz Buchegger schrieb:
> Es war doch auch bisher so, dass eine inline Funktion eine
> Implementierung haben musste.

In C99 bist du (als Programmierer) verantwortlich, die externe
Implementierung dafür zu liefern.  Der Compiler darf sich dann
aussuchen, ob er die inline-Implementierung benutzt oder die
externe.  Natürlich dürfen beide auch komplett was verschiedenes
implementieren. >:-o

Andre H. schrieb:
> Wie meinst denn das jetzt? Ersatzlos streichen geht ja nicht ist ja in
> anderen Dateien in Verwendung...

Aus spi.c nach spi.h verschieben und dort "static inline" schreiben.
Oder halt (wie Karl Heinz empfiehlt) das "inline" wegnehmen und es
in spi.c belassen.

Wer auch immer das in spi.c implementiert hat, hat inline auch bloß
nicht verstanden.  Mit -std=c99 (oder -std=gnu99) wird das fehlende
Verständnis dann zum fatalen Fehler.

von Karl H. (kbuchegg)


Lesenswert?

Jörg Wunsch schrieb:
> Karl heinz Buchegger schrieb:
>> Es war doch auch bisher so, dass eine inline Funktion eine
>> Implementierung haben musste.
>
> In C99 bist du (als Programmierer) verantwortlich, die externe
> Implementierung dafür zu liefern.  Der Compiler darf sich dann
> aussuchen, ob er die inline-Implementierung benutzt oder die
> externe.  Natürlich dürfen beide auch komplett was verschiedenes
> implementieren. >:-o

D.h. wenn man bisher inline richtig gemacht hat, hat sich eigentlich 
nichts verändert.

von Andre H. (andre01)


Lesenswert?

Ok danke,
das Übersetzten hat schon mal geklappt. Gab nur noch ein paar warnungen.
Sobald die Platine und der 168 eigetroffen sind werde ich mal schauen 
was dabei raus kommt...

Danke


André

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.