Hallo,
habe gerade in einer neuen Version einer Bibliothek von mir einen
Prototypen einer Callback-Methode verändert, der an eine Variable als
Zeiger auf eine Funktion zugewiesen wird.
Voher war's
Compiliert man nun Code, der mit einer alten Bibliotheksversion (und
somit dem alten Protoypen) erstellt wurde, lässt sich das problemlos
machen, es wird - richtigerweise - ein Warning generiert:
1
assignment from incompatible pointer type [enabled by default]
So, jetzt kommt das Problem; in älteren AVR-Studios und der Konsole ist
das kein Problem, da bekommt man ja Warnings angezeigt. In den neuen
Studios (Atmel Studio 5.0 - 6.0) macht sich das Studio defaultmäßig
nicht die Mühe, wegen eines Warnings in das "Error List"-Output-Fenster
zu wechseln, ergo viele Programmierer werden das Warning erstmal
übersehen und sich wundern warum der Callback auf einmal nicht mehr
richtig funktioniert (vorausgesetzt haben Debugmöglichkeit, sonst ist
der Fehler noch viel schwerer nachzuvollziehen)
Mein Ansatz wäre jetzt, den Benutzer irgendwie zu zwingen, avr-gcc mit
-Werror aufzurufen, was ohnehin best practice wäre, und falls er das
Flag nicht verwendet, eine entsprechende Meldung à la
"If using TBL-AVR library it is highly recommended to compile with
-Werror set. To ignore this error, pass -DIGNORE_TBL_WARNINGS to
avr-gcc"
ausgeben
Dafür bräuchte ich jetzt in meinem Header so ein Konstrukt
1
#ifndef IGNORE_TBL_WARNINGS
2
#ifndef __WERROR__
3
#error "If using TBL-AVR library it is highly recommended to compile with -Werror set. To ignore this error, pass -DIGNORE_TBL_WARNINGS to avr-gcc"
4
#endif
5
#endif
Ich hab bereits versucht mit folgendem Compileraufruf nach einem Symbol
zu suchen;
avr-gcc -Werror -mmcu=atmega88 -DF_CPU=20000000UL -E -dM testfile.c
Liefert eine elendslange Liste, die aber - sofern ich nichts übersehe -
nichts brauchbares in dieser Sache enthält.
Weiß jemand ob - und wenn ja welches - Symbol definiert wird, wenn der
Compiler mit der -Werror Option aufgerufen wird.
Alternativvorschläge wie man in diesem Fall den
"Endkunden-Programmierer" mit der Nase auf sein Problem des veralteten
Codes stoßen kann sind natürlich ebenfalls sehr willkommen.
LG und Danke
Thomas
Du könntest die Lib mit einer Version versehen und diese abtesten.
Wenn du erst in der aktuellen Version damit anfängst weißt du immerhin,
daß es sich um eine ältere als die aktuelle Version handelt wenn keine
Version vorhanden ist.
Thomas Bergmüller schrieb:> slave->CommandHandler = m3sCmdHandler;
Warum änderst du nicht einfach den Namen "CommandHandler" in irgendwas
anderes? Dann kommt beim Zuweisungsversuch eine Fehlermeldung, ohne von
irgendwelchen Compiler-Flags abhängig zu sein.
Danke für die schnellen Antworten!
@ Johann:
Version gibt's da drinnen schon, aber bringt in dem Fall nichts weil es
ja darum geht, dass alter fremder Code der vor ~ 1 Jahr geschrieben wird
wieder compiliert wird und eine zuweisung nicht mehr aktuell ist.. da
müsste ja dann eigentlich ein
#if VERSION == 2
slave.CommandHandler = cmdHandler_alt;
#else
slave.CommandHandler = cmdHandler_neu;
#endif
im Anwendercode zu finden sein, und das ist ja nicht der Fall.
Warning wird ja richtig ausgegeben, nur verschwindets in den neueren
Atmelstudios leider und das möcht ich irgendwie abfangen.
@Rolf
Läuft im Endeffekt wieder aufs gleiche raus leider;
Ändere ich CommandHandler auf CommandCallback kommt es zu folgendem
Szenario:
1.) CompilerError 'DevComSlave_t' has no member named 'CommandHandler'
2.) Benutzer ändert CommandHandler auf CommandCallback weil er das in
der Doku bzw. Headerfile so findet, denkt aber nicht daran dass sich der
Prototyp auch geändert hat, sprich er lässt die Zuweisung selbst
unverändert.
3.) Compilieren funktioniert, nur dass das eigentliche Problem, nämlich
der falsche Prototyp der zugewiesenen Funktion, noch immer besteht (und
das entsprechende Warning wieder im Hintergrund untergeht). Quasi
gleiches Problem mit anderer Bezeichnung
Ich kann natürlich in der Doku festlegen, dass es empfohlen wird, mit
-Werror zu compilieren, aber das macht dann die Hälfte nicht und bei mir
läufts Telefon heiß... ist eigentlich ein privates Open-Source projekt,
wird aber mittlerweile von meiner Firma in fast allen Projekten
verwendet und auch von Projektpartnern und anderen Firmen gibt es einige
Produkte die die Kommunikation auf der Lib aufbauen... von daher soll
das relativ hieb und stichfest sein ;)
Thomas Bergmüller schrieb:> @Rolf> Läuft im Endeffekt wieder aufs gleiche raus leider;>> Ändere ich CommandHandler auf CommandCallback kommt es zu folgendem> Szenario:>> 1.) CompilerError 'DevComSlave_t' has no member named 'CommandHandler'>> 2.) Benutzer ändert CommandHandler auf CommandCallback weil er das in> der Doku bzw. Headerfile so findet, denkt aber nicht daran dass sich der> Prototyp auch geändert hat, sprich er lässt die Zuweisung selbst> unverändert.
An der Stelle im Header und in der Doku muß natürlich stehen, daß sich
der Prototyp geändert hat. Wer das dann nicht liest und auch noch alle
Warnungen ignoriert (egal, ob die automatisch angezeigt werden oder man
noch irgendwo klicken muß), der ist ja nun wirklich selbst schuld. Ein
bischen Denkfähigkeit würde ich da ich schon voraussetzen.
Falls jemand das Problem nachstellen möchte:
- Kompilierbares Projekt (Atmel Studio 6.0) im Anhang
ODER
- C-Datei OldPrototypeProblem.c im Anhang, compilieren mit Zusatzflags
(zu den üblichen)
@ Rolf
Ja möchte man meinen ;) In der HowTo ist das -Werror flag eh auch schon
empfohlen... Aber das ist halt vielen zu lästig wenn jede unused
variable das Übersetzen verhindert... deswegen muss man sie zu ihrem
Glück zwingen oder zumindest zwingend darauf hinweisen dass das
strengstens empfohlen ist..
Für den Hobbyisten ist das vmtl. kein Problem, in der Wirtschaft wird
aber erfahrungsgemäß wenn was nicht funktioniert gleich mal zum Telefon
gegriffen und beschwert bzw. nachgefragt bevor sich wer die Mühe "macht"
die Doku oder zu lesen
Muss immer alles ein bisschen bullet-proof sein, und gutes Deployment
und Rückwärtskompabilität bzw. entsprechende Fehler machen meiner
Meinung auch den Unterschied zwischen guten und schlechten Bibliothekten
aus - erspart dem Anwender einfach viel Ärger und stundenlanges Suchen
am falschen Ort.
Um ehrlich zu sein, ich hab anfangs bei einem Projekt auch übersehen den
Handler zu ändern und dann 2h darauf verwendet, die restliche Software
zu debuggen bevor ich angefangen hab in der Bibliothek den Fehler zu
suchen.
Thomas Bergmüller schrieb:> - Kompilierbares Projekt (Atmel Studio 6.0) im Anhang>> ODER> - C-Datei OldPrototypeProblem.c im Anhang, compilieren mit Zusatzflags
Anhang vergessen...
Thomas Bergmüller schrieb:> In den neuen> Studios (Atmel Studio 5.0 - 6.0) macht sich das Studio defaultmäßig> nicht die Mühe, wegen eines Warnings in das "Error List"-Output-Fenster> zu wechseln, ...
Dann kannst du wohl nur die Benutzung von AVR Studio 5 oder Atmel
Studio 6 als "unsupported platform" für deine Software deklarieren.
> Liefert eine elendslange Liste, die aber - sofern ich nichts übersehe -> nichts brauchbares in dieser Sache enthält.
Richtig. Kannst du ganz einfach verifizieren: einmal mit, einmal
ohne -Werror die Liste erzeugen und beide vergleichen. Sie sind
identisch. Damit kommt eine präprozessorbasierte Lösung nicht in
Frage.
Thomas Bergmüller schrieb:> Ändere ich CommandHandler auf CommandCallback kommt es zu folgendem> Szenario:>> 1.) CompilerError 'DevComSlave_t' has no member named 'CommandHandler'>> 2.) Benutzer ändert CommandHandler auf CommandCallback weil er das in> der Doku bzw. Headerfile so findet, denkt aber nicht daran dass sich der> Prototyp auch geändert hat, sprich er lässt die Zuweisung selbst> unverändert.>> 3.) Compilieren funktioniert, nur dass das eigentliche Problem, nämlich> der falsche Prototyp der zugewiesenen Funktion, noch immer besteht (und> das entsprechende Warning wieder im Hintergrund untergeht). Quasi> gleiches Problem mit anderer Bezeichnung
Der Part ist mir nicht klar.
Das sollte eigentlich nicht compilieren. Denn in einem Funktionspointer
sind auch die Anzahl und Datentypen der Argumente Bestandteil des
Datentyps des Funktionspointers. Damit ist das die Zuweisung eines
Pointers an einen anderen Pointer mit unterschiedlichem Datentyp.
Und das sollte IMHO eigentlich ein Fehler sein. Im Grund nichts anderes
als
int * pA;
double * pB;
pA = pB;
nur eben mit Funktionspointern.
Klar, mit einem Cast kann man das immer noch aushebeln. Aber wer Pointer
umcastet, sollte schon sehr genau wissen, was er tut.
Karl Heinz Buchegger schrieb:> Denn in einem Funktionspointer sind auch die Anzahl und Datentypen der> Argumente Bestandteil des Datentyps des Funktionspointers. Damit ist das> die Zuweisung eines Pointers an einen anderen Pointer mit> unterschiedlichem Datentyp.> Und das sollte IMHO eigentlich ein Fehler sein.
Ist es aber in C nicht.
> Im Grund nichts anderes als>> int * pA;> double * pB;>> pA = pB;>> nur eben mit Funktionspointern.
Und auch da kommt nur eine Warnung.
Ja, ist Bestandteil des Datentyps und die Zuweisung natürlich falsch.
GCC behandelt das aber - in diesem Fall sehr zu meinem Bedauern - nur
mit einem Warning und keinem Error.
Gibt ja auch weniger schwere Fälle wo's nur syntaktisch nicht schön ist,
z.b. unsigned char und char Arrays (solange nur bitweise und nicht
arithmetisch verwendet wird), Parameter im Prototyp mit und ohne
vorangestelltem const usw.
Genau aus dem Grund, weil's gcc eben nicht macht, es in diesem Fall aber
zu schwerwiegenden und vor allem schwer diagnostizierbaren Fehlern kommt
(ist ja genau der Übergabepunkt aus der Library, die nicht gedebuggt
werden kann) und dem Anwendungsprogramm, möchte ich das Warning
irgendwie verschärfen, sodass es nicht so leicht übergangen werden kann
Thomas Bergmüller schrieb:> Ja, ist Bestandteil des Datentyps und die Zuweisung natürlich falsch.> GCC behandelt das aber - in diesem Fall sehr zu meinem Bedauern - nur> mit einem Warning und keinem Error.>> Gibt ja auch weniger schwere Fälle wo's nur syntaktisch nicht schön ist,> z.b. unsigned char und char Arrays (solange nur bitweise und nicht> arithmetisch verwendet wird), Parameter im Prototyp mit und ohne> vorangestelltem const usw.>> Genau aus dem Grund, weil's gcc eben nicht macht, es in diesem Fall aber> zu schwerwiegenden und vor allem schwer diagnostizierbaren Fehlern kommt> (ist ja genau der Übergabepunkt aus der Library, die nicht gedebuggt> werden kann) und dem Anwendungsprogramm, möchte ich das Warning> irgendwie verschärfen, sodass es nicht so leicht übergangen werden kann
Aus genau dem Grund gibt's -Werror. Und wenn einem die
Holzhammermethode zu viel ist, kann man auch einzelne Warnungen im
Fehler wandeln mit -Werror=...
Wer Diagnosticsc nicht nutzen oder beachten möchte, der muss sich halt
im erzeugten Code den Wolf suchen...