Hallo,
ich bin es wieder.
Jetzt da das LCD läuft, bin ich gerade dabei Funktionen für die Anzeige
zu schreiben.
Bis zur Funktion
1
voidWert_Ausgabe(uint,char*);
in lcd_funktionen.c ging auch alles gut. Doch jetzt meint mein avr-gcc,
dass er unit und uint_8 nicht mehr mag. Woran kann das liegen?
Es kommt folgende Fehlermeldung:
lcd_funktionen.h:37: Fehler: expected »)« before »char«
5
make: *** [main.o] Fehler 1
Ersetze ich uint durch unsigned char oder kommentiere die betroffene
Funktion aus, dann bemängelt er die Zeilen in lcd_routinen in denen
uint_8 auftritt.
Ich sehe einfach keinen Grund dafür...
Kann mir da einer weiterhelfen...
Gruß
Alex
Wann ich mal so gaz naiv fragen darf: Was soll der 'uint' denn
darstellen? Einen unsigned int? Oder einen uint8_t? Ist das irgendwo
definiert?
kleinersläschhinthinthintgrößer
HTH
P.S.: Die 'case 0:' in Wert_Ausgabe() solltest auch nochmals ansehen.
das folgende in deinen lcd_funktionen ist eine Katastrophe, überleg mal
warum !!!!
>>////////////////////////////////////////////////////////////////////// //>>// Wandelt float in char um>>char* float_zu_char(float z)>>{>> char string[6];>> int g = z;>> int n = abs((z-g)*10);>> sprintf(string,"%4i,%1i",g,n);>> return string;>>}
ein Hinweis: string
alex44 schrieb:> Doch jetzt meint mein avr-gcc,> dass er unit und uint_8 nicht mehr mag. Woran kann das liegen?
Wo ist denn "unit" definiert?
alex44 schrieb:> Ersetze ich uint durch unsigned char oder kommentiere die betroffene> Funktion aus, dann bemängelt er die Zeilen in lcd_routinen in denen> uint_8 auftritt.
Man schreibt nicht "bemängelt" sondern copy&paste die exakte
Fehlermeldung.
Ist das denn so schwer?
Peter
Wenn dir uint und uint_8 so gut gefallen (?), dann musst du schon
mal suchen, wo die definiert sind. Einfacher ist es, die üblichen
Definitionen zu verwenden: 'int??_t' bzw. 'uint??_t'
(Ich tippe mal auf 'schläfrig')
alex44 schrieb:> in lcd_funktionen.c ging auch alles gut. Doch jetzt meint mein avr-gcc,> dass er unit und uint_8 nicht mehr mag.
Bedeutet "nicht mehr", daß es in deinem Programm andere Stellen gibt, wo
er sich darüber nicht beschwert? Dann schau mal, welche Header dort
eingebunden sind. Irgendeiner davon muß diese Namen ja definieren.
Klaus schrieb:>>>///////////////////////////////////////////////////////////////////// ///>>>// Wandelt float in char um>>>char* float_zu_char(float z)>>>{>>> char string[6];>>> int g = z;>>> int n = abs((z-g)*10);>>> sprintf(string,"%4i,%1i",g,n);>>> return string;>>>}>>> ein Hinweis: string
Davon mal abgesehen, dass es funktioniert, habe ich aus string data
gemacht. War wirklich nicht schön.
Ralf schrieb:> (Ich tippe mal auf 'schläfrig')
Volltreffer:
Habe die switch-case bereinigt und aus uint unsigned gemacht.
Jetzt kommt die Meldung:
lcd_routinen.h:79: Fehler: expected »)« before »spalte«
4
lcd_routinen.h:83: Fehler: expected »)« before »data«
5
lcd_routinen.h:93: Fehler: expected »)« before »code«
6
lcd_routinen.h:97: Fehler: expected »)« before »data«
7
lcd_funktionen.c: In Funktion »lcd_starten«:
8
lcd_funktionen.c:24: Warnung: Implizite Deklaration der Funktion »lcd_setcursor«
9
lcd_funktionen.c: In Funktion »float_zu_char«:
10
lcd_funktionen.c:50: Warnung: Funktion liefert Adresse einer lokalen Variablen zurück
11
make: *** [lcd_funktionen.o] Fehler 1
Komisch ist, dass die lcd_routinen ohne die lcd_funktionen problemlos
laufen. Liegt das vielleicht am Makefile? Da habe ich die
lcd_funktionen.c wie folgt hiinzugefügt:
1
SRC = $(TARGET).c lcd_routinen.c lcd_funktionen.c
An den Routinen habe ich im Nachhinein nichts mehr geändert... (Habe sie
sogar durch das Original noch mal ersetzt...)
alex44 schrieb:> Klaus schrieb:>>>>//////////////////////////////////////////////////////////////////// ////>>>>// Wandelt float in char um>>>>char* float_zu_char(float z)>>>>{>>>> char string[6];>>>> int g = z;>>>> int n = abs((z-g)*10);>>>> sprintf(string,"%4i,%1i",g,n);>>>> return string;>>>>}>>>>>> ein Hinweis: string>> Davon mal abgesehen, dass es funktioniert, habe ich aus string data> gemacht. War wirklich nicht schön.
Wie du deinen String nennst ist völlig Latte.
1.) String ist lokal definiert und ist bei verlassen der Funktion
float_zu_char() nicht mehr gültig.
2.) dein String ist zu kurz: "1234,5" verbrät schon 6 Zeichen, die
abschließende NULL landet im Nirvana.
alex44 schrieb:> Jetzt kommt die Meldung:avr-gcc -c -mmcu=atmega32 -I. -gstabs -Os> -Wall -Wstrict-prototypes -std=gnu99 lcd_funktionen.c -o lcd_funktionen.o> In file included from lcd_funktionen.c:4:> lcd_routinen.h:79: Fehler: expected »)« before »spalte«> lcd_routinen.h:83: Fehler: expected »)« before »data«> lcd_routinen.h:93: Fehler: expected »)« before »code«> lcd_routinen.h:97: Fehler: expected »)« before »data«
Ich denke mal, die Variablen sind nicht deklariert -> 'stdint.h'
einbinden
> lcd_funktionen.c: In Funktion »lcd_starten«:> lcd_funktionen.c:24: Warnung: Implizite Deklaration der Funktion> »lcd_setcursor«
Da 'lcd_setcursor' nicht deklariert wurde (wegen Fehler oben), könnte
das jetzt möglicherweise die Deklaration sein (ist es aber nicht).
> lcd_funktionen.c: In Funktion »float_zu_char«:> lcd_funktionen.c:50: Warnung: Funktion liefert Adresse einer lokalen> Variablen zurück
Das wurde schon mal angemäkelt! Die Variable string existiert nicht mehr
nach dem Funktionsaufruf!! Wenn doch: blanker Zufall!
> make: *** [lcd_funktionen.o] Fehler 1
Nimm ausschließlich die 'übersichtlichen' Typbezeichner uintXX_t und
intXX_t. Dazu noch char. Das dürfte dann reichen.
Achso, jetzt verstehe ich auch den Hinweis mit dem string.
Ich darf nicht char data[6] schreiben, sondern muss char*data nehmen.
Weil es sonst ein Array und kein string ist.
alex44 schrieb:> Achso, jetzt verstehe ich auch den Hinweis mit dem string.>> Ich darf nicht char data[6] schreiben, sondern muss char*data nehmen.> Weil es sonst ein Array und kein string ist.
... ganz schnell vergessen!
Wenn ich #include "lcd_routinen.h" aus dem Kopf von lcd_funktionen.c
entferne, dann bemängelt er die routinen.h nicht mehr. Dafür aber die
fehlenden Deklarationen...
alex44 schrieb:> Achso, jetzt verstehe ich auch den Hinweis mit dem string.>> Ich darf nicht char data[6] schreiben, sondern muss char*data nehmen.> Weil es sonst ein Array und kein string ist.
Hmmm... wie schon so oft:
C-Buch kaufen und mal nachschauen: z.B.Kernighan/Ritchie
"char *data" definiert lediglich einen Zeiger auf char-Elemente, der
"data" heißt. Das Lokal/Global-Problem hast du damit nicht gelöst und
die Länge deines Strings auch nicht.
alex44 schrieb:> Wenn ich #include "lcd_routinen.h" aus dem Kopf von lcd_funktionen.c> entferne, dann bemängelt er die routinen.h nicht mehr. Dafür aber die> fehlenden Deklarationen...> [/code]
OK, weiterprobieren, du wirst das schon schaffen... (oder die Hinweise
befolgen, die schon genannt wurden)
alex44 schrieb:> Achso, jetzt verstehe ich auch den Hinweis mit dem string.
Nein, hast Du noch nicht verstanden.
> Ich darf nicht char data[6] schreiben, sondern muss char*data nehmen.> Weil es sonst ein Array und kein string ist.
Und wo befindet sich der Speicher, in dem die Daten abgelegt werden?
Durch die Deklaration des Pointers wird nur der Speicher alloziert, den
der Pointer selbst belegt.
Und der Pointer selbst ist auch nicht mehr definiert, Sobald die
Funktion verlassen wird. C ist an der Stelle sehr minimalistisch.
Also die int-Typen sind über avr/io.h definiert:
avr/io.h -> avr/sfr_defs.h -> inttypes.h -> stdint.h
Trotzdem scheint er
1
voidlcd_setcursor(uint8_tspalte,uint8_tzeile);
zu bemängeln. Obwohl er das vorher nicht tat. Es gibt offensichtlich
auch keinen Grund dafür.
Daniel V. schrieb:> C-Buch kaufen und mal nachschauen:
Tja. Ein C-Buch von SUSE-Press liegt vor mir.
Mit char* übergebe ich Adressen, keine Werte. Das hieße ich müsste eine
Adresse übergeben,
1
char*float_zu_char(char*data,floatz)
2
{
3
intg=z;
4
intn=abs((z-g)*10);
5
sprintf(data,"%4i,%1i",g,n);
6
returndata;
7
}
8
9
intmain(void)
10
{
11
chardummi[7];
12
lcd_string(float_zu_char(dummi,-123.4));
13
return0;
14
}
Das müsste jetzt eigentlich passen.
Aber das mit den int-Typen ist mir immer noch schleierhaft
alex44 schrieb:> Also die int-Typen sind über avr/io.h definiert:> avr/io.h -> avr/sfr_defs.h -> inttypes.h -> stdint.h>> Trotzdem scheint er>
1
>voidlcd_setcursor(uint8_tspalte,uint8_tzeile);
2
>
> zu bemängeln. Obwohl er das vorher nicht tat. Es gibt offensichtlich> auch keinen Grund dafür.
Wenn der Compiler meckert, dann hat er Recht.
Was bemängelt er denn?
alex44 schrieb:> lcd_funktionen.c: In Funktion »lcd_starten«:> lcd_funktionen.c:24: Warnung: Implizite Deklaration der Funktion> »lcd_setcursor«> make: *** [lcd_funktionen.o] Fehler 1
Die Funktion "lcd_setcursor" ist in "lcd_functionen.h" nicht deklariert.
Woher soll der Compiler wissen, dass diese Funktion schon existiert?
Deswegen "Implizite Deklaration der Funktion »lcd_setcursor«", er
bastelt sich seine eigene Funktion, in der keine Übergabeparameter
vorkommen.
Edit:
Ach nee, Käse.
Du solltest dies hier:
Hm...
Die Funktion lcd_setcurser ist in lcd_routinen.h deklariert.
lcd_routinen.h wird in der main.c und der lcd_funktionen.c eingebunden.
Damit müssten beide auch lcd_setcurser kennen.
Und wenn ihn das nicht reichen würde, hätte er auch lcd_init() und
lcd_string() bemängeln müssen.
Ich denke, wie oben schon genannt, dass das nur an dem Fehler
1
In file included from lcd_funktionen.c:3:
2
lcd_routinen.h:79: Fehler: expected »)« before »spalte«
3
lcd_routinen.h:83: Fehler: expected »)« before »data«
4
lcd_routinen.h:93: Fehler: expected »)« before »code«
5
lcd_routinen.h:97: Fehler: expected »)« before »data«
liegt. Und genau die kann ich mir nicht erklären. Zumal es den vor
lcd_funktionen nicht gab.
alex44 schrieb:> Also die int-Typen sind über avr/io.h definiert:> avr/io.h -> avr/sfr_defs.h -> inttypes.h -> stdint.h
Somit solltest du "stdint.h" in deine Headers mit einbinden. Ansosnten
weiß der Compiler nicht, was "uint8_t" ist.
alex44 schrieb:> Brauchte nur die includes umsortieren :)
Richtig und Falsch zugleich.
Falls du in einem anderen C-File "lcd_routinen.h" einbindest, wirst du
unter Umständen das Gleiche Problem haben. Deswegen gehört die
"stdint.h" als #include in die "lcd_routine.h" hinein.
Man bindet zuerst immer die globalen Header <xx.h> ein und danach die
lokalen "xx.h".
Gute Praxis ist aber auch, nötige globale Header mit in den lokalen
einzubinden.
Peter
Daniel V. schrieb:> Falls du in einem anderen C-File "lcd_routinen.h" einbindest, wirst du> unter Umständen das Gleiche Problem haben. Deswegen gehört die> "stdint.h" als #include in die "lcd_routine.h" hinein.
Ich halte es für schlechten Programmierstil, includes in includes
einzubinden. Es gehört hier halt in jeden C-Source, der die LCD-Routinen
nutzt:
#include <stdint.h>
#include "lcd_funktionen.h"
So sollte man es als Programmierer, welcher eine Source-Lib zur
Verfügung stellt, auch dokumentieren.
Gruß,
Frank
Frank M. schrieb:> Ich halte es für schlechten Programmierstil, includes in includes> einzubinden.
Andere Leute sind da anderer Meinung, beide Meinungen haben ihre
Berechtigung. Man sollte aber die eine oder die andere Methode
dann konsequent durchziehen, nicht mal so, mal so.
Jörg Wunsch schrieb:> Frank M. schrieb:>> Ich halte es für schlechten Programmierstil, includes in includes>> einzubinden.>> Andere Leute sind da anderer Meinung, beide Meinungen haben ihre> Berechtigung. Man sollte aber die eine oder die andere Methode> dann konsequent durchziehen, nicht mal so, mal so.
Gerade wollte ich einen Beitrag verfassen, bei dem mich deine Meinung
interessiert.
Ich finde es "bequem", wenn ich nur eine Header einbinden muss, z.B.
"lcd_routinen.h". Was diese Header noch für Headers braucht interessiert
mich wirklich nicht,sonst pasiert mir das, was alexx44 passiert ist, es
kommt eine Fehlermeldung und das Suchen geht los. Habe ich dann eine
fehlende Header eingebunden braucht die vielleicht wieder eine.
Ich denke bei den C-Libs wird das ja auch so gemacht, dass man nur einen
Header einbinden muss.
Die Vorgehensweise, Headerdateien in einer oder sehr wenigen
projektspezifischen Headerdateien zu bündeln, ist äußerst ratsam,
insbesondere wenn Seiteneffekte durch die unterschiedliche Reihenfolge
der Einbindung entstehen können.
Solch eine projektspezifische Bündeldatei sollte jedoch keine oder nur
wenige andere Anweisungen enthalten. Ggf. können vor den ganzen
#include-Anweisungen noch einzelne Präprozessordefinitionen stehen, die
das Einbinden der untergeordneten Headerdateien steuern, z.B.
Debugschalter.
Andreas Schweigstill schrieb:> Die Vorgehensweise, Headerdateien in einer oder sehr wenigen> projektspezifischen Headerdateien zu bündeln, ist äußerst ratsam,
Bei großen Projekten ist es aber blöd, wenn wegen einer kleinen Änderung
in einer einzelnen Header-Datei das gesamte Projekt neu kompiliert
werden muss. Ok, bei Projekten, die auf µC laufen, ist das evtl. gerade
noch akzeptabel.
Daniel V. schrieb:> Ich finde es "bequem", wenn ich nur eine Header einbinden muss, z.B.> "lcd_routinen.h". Was diese Header noch für Headers braucht interessiert> mich wirklich nicht
Dem kann ich nur zustimmen. Meine Erfahrung hält sich zwar noch stak in
Grenzen, aber in Punkto Fehler machen ist es schon sehr hilfreich nur
eine header-Datei zu bemühen.
Letztlich werden diese dadurch auch flexibler und so manche c-Source im
Kopf übersichtlicher.
alex44 schrieb:> Letztlich werden diese dadurch auch flexibler und so manche c-Source im> Kopf übersichtlicher.
Wenn man eigene Makefiles erstellen muss, ist die Formulierung der
Abhängigkeiten bei ineinandergeschachtelten Includes u.U. komplizierter
und fehleranfälliger.
Die Regel, includes nur in C-Dateien einzubauen, ist doch ganz einfach:
Erst System-Includes (wie <stdint.h>)
Dann Anwender-Lib-Includes (wie "lcd_funktionen.h")
Hätte sich der TO an diese einfache Regel gehalten, hätte er die obigen
Probleme doch gar nicht gehabt.
Gruß,
Frank
alex44 schrieb:> Letztlich werden diese dadurch auch flexibler und so manche c-Source im> Kopf übersichtlicher.
Sehe ich anders: Man versteht gar nicht mehr, warum etwas funktioniert
bzw. nicht funktioniert. In Deinem Fall müsste man sich rekursiv durch
die Includes wühlen. Wenn diese nur in der C-Datei stehen, ist die
Struktur platt und auf einen Blick nachvollziehbar.
Gruß,
Frank
Frank M. schrieb:> Ich halte es für schlechten Programmierstil, includes in includes> einzubinden.
Ich dagegen halte es für sehr schlechten Programmierstil, wenn ein
#include Fehler produziert (für mich ist der Header dann kaputt), weil
noch von diesem Header benötigte Sachen fehlen. Ein Header muß
"self-contained" sein.
Frank M. schrieb:> Wenn man eigene Makefiles erstellen muss, ist die Formulierung der> Abhängigkeiten bei ineinandergeschachtelten Includes u.U. komplizierter> und fehleranfälliger.
Die erzeugt mir GCC doch eh automatisch.
Frank M. schrieb:> alex44 schrieb:>> Letztlich werden diese dadurch auch flexibler und so manche c-Source im>> Kopf übersichtlicher.>> Sehe ich anders: Man versteht gar nicht mehr, warum etwas funktioniert> bzw. nicht funktioniert. In Deinem Fall müsste man sich rekursiv durch> die Includes wühlen. Wenn diese nur in der C-Datei stehen, ist die> Struktur platt und auf einen Blick nachvollziehbar.
Dafür muß man sich halt beim Schreiben des C-Files durch die Header
wühlen, um erstmal rauszufinden, was man alles noch mit einbinden muß,
damit ein einfaches #include nicht zu seitenweise Fehlermeldungen führt.
Rolf Magnus schrieb:> Ich dagegen halte es für sehr schlechten Programmierstil, wenn ein> #include Fehler produziert (für mich ist der Header dann kaputt), weil> noch von diesem Header benötigte Sachen fehlen. Ein Header muß> "self-contained" sein.
Sehe ich nicht so :-)
> Frank M. schrieb:>> Wenn man eigene Makefiles erstellen muss, ist die Formulierung der>> Abhängigkeiten bei ineinandergeschachtelten Includes u.U. komplizierter>> und fehleranfälliger.>> Die erzeugt mir GCC doch eh automatisch.
GCC ist nicht der Mittelpunkt des Universums. Außerdem schrieb ich "Wenn
man eigene Makefiles erstellen muss...". Betonung liegt auf "Wenn".
> Frank M. schrieb:> Dafür muß man sich halt beim Schreiben des C-Files durch die Header> wühlen, um erstmal rauszufinden, was man alles noch mit einbinden muß,> damit ein einfaches #include nicht zu seitenweise Fehlermeldungen führt.
Wenn die Doku stimmt, muss man das nicht. Wenn man eine LIB
bereitstellt, sollte diese auch in der Synopsis dokumentiert sein.
Ich nehme mal irgendeine UNIX-/Linux-Manpage:
http://linux.die.net/man/3/termios
Nach Deiner Auffassung sollte nun <termios.h> das <unistd.h> selbst
includieren?
Aber wie gesagt: alles Auffassungssache, wir sollten das nicht in einen
Krieg verwandeln. Ich kann mit abweichenden Meinungen durchaus leben,
solange der Autor dann auch durch geeignete Maßnahmen Mehrfach-Includes,
die durch Schachtelung auf verschiedenen Ebenen immer wieder passieren
können, auch durch
#ifndef MEIN_INCLUDE_H
#define MEIN_INCLUDE_H
...
#endif
geordnet abfängt.
Frank M. schrieb:> Ich nehme mal irgendeine UNIX-/Linux-Manpage:>> http://linux.die.net/man/3/termios>> Nach Deiner Auffassung sollte nun <termios.h> das <unistd.h> selbst> includieren?
Das war wohl eher ein Eigentor :)
Hast Du mal in die erwähnten Header (termios.h/unistd.h) reingeschaut,
wieviele weitere includes da drin stehen? Insbesondere z.B. die Zeilen
1
#include<stddef.h>
2
#include<getopt.h>
dürften nach Deiner Definition dann nicht in der unistd.h mit drin sein
und müßten mit in der Manualpage dokumentiert sein.
... schrieb:> Das war wohl eher ein Eigentor :)
Okay, ich gebe mich geschlagen :-)
Wie gesagt, ich wollte da auch keine Religion draus machen. Ich schrieb
ja, dass ich geschachtelte Includes akzeptiere, wenn durch entsprechende
Maßnahmen den notgedrungen entstehenden Mehrfach-Includes vorgebeugt
wird. Das ist bei Linux auch selbstverständlich gegeben.
Frank M. schrieb:> Okay, ich gebe mich geschlagen :-)
Es zeigt, dass du man-pages liest. Nur hinkt hier die man-page der
Realität etwas hinterher. Eine Beobachtung die ich in den letzten Jahren
schon öfter gemacht habe, die Software ist aktueller als die Doku, auch
bei kommerziellen Systemen.
Frank M. schrieb:> GCC ist nicht der Mittelpunkt des Universums. Außerdem schrieb ich "Wenn
Ich schätze es sehr, dass ich mit einem -sehr guten- Werkzeug fast alle
Systeme/Plattfomen abdecken kann: 8-Bit AVR, AP7000, ARM, x86 in 32- und
64-Bit, SPARC in 32- und 64-Bit, PPC in 32- und 64-Bit. Nur unter
Windows klemmts noch ein wenig --- aber eines Tages ...