Hallo ihr Experten,
ich bekomme beim kompilieren immer eine "implicit declaration" Warnung.
Das Programm läuft zwar trotzdem korrekt aber ich wüsste gerne warum das
falsch ist.
Konkret geht es um den Aufruf einer Funktion innerhalb einer If
Abfragefunktion. Dort wird aufgerufen:
void tasterabfrage(void)
{
if (taster ==1)
{
timereset();
}
}
Die aufzurufende Funktion selbst ist folgendermaßen deklariert:
void timereset(void)
{
variable1=variable2;
}
Die Reihenfolge ist nicht ganz unwichtig. Die Deklaration muß vor dem
ersten Aufruf stehen, ansonsten kennt der Compiler die dort noch nicht.
Daher schreibt man die Deklaration an den Anfang.
Hi,
die Funktion ist aber erst definiert, nachdem Du sie schonmal genutzt
hast.
Deshalb gibt es bei der Benutzung eine Warnung und der Compiler macht
wüste Spekulationen über Parameter und Rückgabewert sowie deren
Datentypen.
Also zunächst alle Funktionen deklarieren :
1
voidtasterabfrage(void);
2
voidtimereset(void);
So etwas kann gerne auch in einer Header-Datei geschehen, wenn die
Funktionen in mehreren Quelltexten genutzt werden.
Dann die Funktionen nach und nach definieren :
1
voidtasterabfrage(void)
2
{
3
...
4
}
5
6
voidtimereset(void)
7
{
8
...
9
}
Wenn Du es ganz fein säuberlich machen willst, achtest Du darauf, dass
es nur genau eine Deklaration für jede Funktion gibt (für Variablen gilt
das ähnlich).
Sprich, wird die Funktion in einer .c - Datei verwendet, steht die
Deklaration vor den Funktionsdefinitionen in dieser .c - Datei. Und
damit sich auch kein anderer Quelltext dran vergeht, sind die Funktionen
als static gekennzeichnet.
Brauchst Du die Funktion in mehreren Quelltexten, so schreibt man die
Deklaration einmal in einer .h-Datei. Wobei auch die .c-Datei, die die
Funktion definiert, jene .h-Datei einbindet.
Das stellt sicher, dass sich alle einig sind, welchen Typ Rückgabewert
und Parameter haben.
Weil merke : wenn es mehrere Deklarationen gibt, könnten sie
unterschiedlich sein. Und weil laut Murphy alles schief geht, was schief
gehen kann, werden sie irgendwann unterschiedliche Parametertypen haben,
was zu witzigen, aber schlecht zu behebenden Fehlfunktionen führt.
Und bitte jetzt nicht damit kommen, dass das bei Arduino auch anders
geht. Ja, die haben einen Parser eingebaut, der zu allen Funktionen
Deklarationen erstellt und automatisch dem Compiler zur Verfügung
stellt, so dass sich Programmieranfänger damit nicht herumplagen müssen.
Ralf schrieb:> ich bekomme beim kompilieren immer eine "implicit declaration" Warnung.> Das Programm läuft zwar trotzdem korrekt aber ich wüsste gerne warum das> falsch ist.
Es gibt Programme, die ohne (korrekte) Prototypen nicht korrekt
übersetzt werden (können). Um solche Fehler zu vermeiden, warnt gcc —
und zwar auch dann, wenn der erzeugte Code das tut, was er soll.
Daher wird für avr-gcc empfohlen, auch folgende Schalter bzw.
Diagnostics zu aktivieren:
-Wmissing-prototypes
-Wstrict-prototypes
Weil es wie gesagt für manche ABIs / Architekturen sein kann (z.B. für
avr) dass ohne Prototypen kein funktionales Programm zu erhalten ist,
sollten man jedoch die strikteren
-Werror=missing-prototypes
-Werror=strict-prototypes
verwenden.
Wenn die Funktionen in einer Datei stehen und man keine Deklarationen
macht/machen will, dann muss die Funktion, die zuerst in einer Routine
benutzt wird, auch zu oberst im File kommen.
Weil das umständlich ist, den Code darauf zu prüfen, macht man die
genannten Deklarationen.
Hi Johann, danke für den Hinweis. Gibt es noch andere Empfehlungen,
welche Warn-Parameter man aktivieren sollte, um ähnliche Probleme
schnell aufzudecken?
Ich mache immer -W -Wall -Wextra -Wstrict-overflow -Waddr-space-convert.
Aber das scheint ja nicht der Weisheit letzter Schluss zu sein.
Zumindest hat dein Hinweis bei einem meiner Quelltexte ein kleines
Problem zu Tage gefördert.
-pedantic spuckt halt viel wirres Zeug aus, das nicht wirklich weiter
hilft. Alleine die ganzen Warnungen zu Binärkonstanten (die ich zu
Hunderten benutze) überfluten den Bildschirm völlig.
Der Sinn von Warnungen ist es, dich auf Dinge hinzuweisen, die du anders
besser machen könntest. Auch wenn ein pedantischer Compiler meist nur
auf Prinzipien rumreitet, so ganz unrecht hat er meist nicht. :-)
Es gibt in C keine Binärkonstanten, also ist dein Code schonmal kein C.
Egal, wie offensichtlich es ist, was du hinschreibst. ;-)
Fakt ist, dass Binärkonstanten aber korrekt implementiert sind und
funktionieren und sicher auch nicht geplant ist, dieses jemals wieder
aus dem gcc zu entfernen. Diese Warnung ist völlig praxisfern und mutet
steinzeitlich an. Genauso die Warnung vor doppelten Semikola.
Wer Binärkonstanten benutzt, tut dies aus gutem Grund. Meinst du, der
Code wird lesbarer und besser, wenn ich es als Hex oder Dez schreibe und
beim Verstehen des Codes jedesmal im Kopf rechnen darf!?
Ist aber auch egal. -pedantic führt keine anderen hilfreichen Meldungen
zutage, so wie es z.B. -Wmissing-prototypes tat. Meine Frage war, ob es
noch mehr praxistaugliche Warn-Schalter gibt, die man auch sinnvoll
verwenden sollte.
Tim schrieb:> Meinst du, der> Code wird lesbarer und besser, wenn ich es als Hex oder Dez schreibe und> beim Verstehen des Codes jedesmal im Kopf rechnen darf!?
Der Code wird besser, wenn du den Compiler rechnen lässt und Namen für
Konstanten vergibst.
Binärkonstanten sind überflüssig.
Tim schrieb:> Fakt ist, dass Binärkonstanten aber korrekt implementiert sind und> funktionieren und sicher auch nicht geplant ist, dieses jemals wieder> aus dem gcc zu entfernen.
Auf allen Architekturen? Das war m.W. lange eine Spezialität vom
AVR-GCC.
Tim schrieb:> Genauso die Warnung vor doppelten Semikola.
Sowas nehme ich - wie auch Leerzeichen am Ende der Zeile - als
oberflächliches Maß für die Qualität eines Quelltextes. Im Sinne von:
Wie ordentlich hat der Autor gearbeitet.
Einen Text bewerte ich auch nach der Rechtschreibfehlerdichte. Wem die
Form egal ist, dem kann auch der Inhalt nicht sehr wichtig sein.
Tim schrieb:> Meinst du, der Code wird lesbarer und besser,> wenn ich es als Hex oder Dez schreibe und> beim Verstehen des Codes jedesmal im Kopf rechnen darf!?
Wenn du sinnvolle Namen benutzt, ja.
Auf einem 8-Bitter kann man Binärkonstanten noch sinnvoll einsetzen, auf
einem 32-Bitter nicht.
Tim schrieb:> Ist aber auch egal. -pedantic führt keine anderen hilfreichen Meldungen> zutage, so wie es z.B. -Wmissing-prototypes tat.
"Hilfreich" ist aber deine persönliche Meinung. ;-)
S. R. schrieb:> Der Sinn von Warnungen ist es, dich auf Dinge hinzuweisen, die du anders> besser machen könntest.
Eigentlich ist der Sinn, auf Dinge hinzuweisen, die mit einer gewissen
Wahrscheinlichkeit fehlerhaft sind. Die kann man dann nicht besser
machen, sondern richtiger.
Oliver
Tim schrieb:> Fakt ist, dass Binärkonstanten aber korrekt implementiert sind und> funktionieren und sicher auch nicht geplant ist, dieses jemals wieder> aus dem gcc zu entfernen. Diese Warnung ist völlig praxisfern und mutet> steinzeitlich an. Genauso die Warnung vor doppelten Semikola.
Das hat nichts mit "steinzeitlich" zu tun. Das Handbuch sagt explizit
folgendes zu -pedantic:
"Issue all the warnings demanded by strict ISO C and ISO C++; reject all
programs that use forbidden extensions, and some other programs that do
not follow ISO C and ISO C++. For ISO C, follows the version of the ISO
C standard specified by any -std option used."
Es ist also genau dafür da, bei allem zu warnen, das nicht strikt ISO-C
ist, oder anders gesagt, bei Konstrukten, für die ISO C vorschreibt,
dass der Compiler mindestens warnen muss.
> Ist aber auch egal. -pedantic führt keine anderen hilfreichen Meldungen> zutage, so wie es z.B. -Wmissing-prototypes tat.
Wenn man nicht an ISO-C-Konformität interessiert ist, dann mag das sein.
Oliver S. schrieb:> Eigentlich ist der Sinn, auf Dinge hinzuweisen, die mit einer gewissen> Wahrscheinlichkeit fehlerhaft sind.
Wenn du Dinge tust, die nicht dem C-Standard entsprechen, dann sind sie
entsprechend des C-Standards ziemlich sicher fehlerhaft (d.h.
implementation-defined oder undefined).
Falls dich das nicht interessiert, programmierst du kein C, sondern
einen C-ähnlichen Dialekt des gcc auf einer bestimmten Architektur.
Wieviel "avr-gcc" für dich akzeptabel ist, kannst nur du wissen. Ich
habe dir "-pedantic" auch nur vorgeschlagen, eben aus diesem Grund.
S. R. schrieb:> Wieviel "avr-gcc" für dich akzeptabel ist, kannst nur du wissen. Ich> habe dir "-pedantic" auch nur vorgeschlagen, eben aus diesem Grund.
Ich bin vermutlich nicht das du, das du meinst, aber egal.
Oliver
Tim schrieb:> Alleine die ganzen Warnungen zu Binärkonstanten (die ich zu> Hunderten benutze) überfluten den Bildschirm völlig.
Macht der das auch wenn man Gnu Extensions über --std=gnu11 einschaltet?
Kann aber sein, weil das IIRC nur auf AVR tut.
Hunterte Binärkonstanten sind aber auch eher schlechter Stil, da die
IMHO fehlerträchtiger als Hex sind.
Oliver S. schrieb:> Ich bin vermutlich nicht das du, das du meinst, aber egal.
Stimmt, ich meinte Tim - also den, von dem die letzte Diskussion
ausging. :-)
Ja, auch dann.
Die Binärkonstanten sind alles Sachen, wo man gleich erkennen sollte,
welches Bit gesetzt ist oder nicht. Beispiel: Konfiguration von
I2C-Geräten. Wenn ich da Hex oder Dez schreibe, kann ich das nicht
sofort sehen.
Aber ist auch egal. Pedantic ist nicht für mich geeignet, da es keinen
Informationsvorteil bringt. Aber eventuell hat ja noch einer einen
Geheimtipp für andere Warnschalter.
Tim schrieb:> wo man gleich erkennen sollte, welches Bit gesetzt ist oder nicht.
Dafür sind Binärkonstanten aber auch nicht hilfreich. Besser sind
sprechende Namen der Bits bzw. der Bit-Werte, die dann mit OR
kombiniert werden. So macht es der Rest der Welt.
Ansonsten ist der intellektuelle Sprung zu tatsächlich standardkonformen
Hexadezimalkonstanten nun wirklich nicht gigantisch; man muss nur 16
Bitkombinationen "lernen", um ein Nibble zu verstehen. Damit beschäftigt
man sich mal 'ne Woche lang, dann kann man's für den Rest des Lebens und
braucht keine Binärkonstanten. Die werden obendrein bei mehr als 8 Bit
reichlich unübersichtlich, was man von Hexkonstanten erst jenseits der
32 Bit sagen kann.