ich hab mir hier eine Log-Routine gebastelt, die auch printf() Attribute
versteht.
Da geht man natürlich am besten mit va_list zu Werke, da es einmal z. b. 2,
und einmal auch 4 Attribute sein können, was man vorher nie weiß.
Sieht so aus:
void logMe (FILE* ofile, const char* fmtStr, ...)
{
va_list arg_p;
va_start (arg_p, fmtStr); /* init. Argumentenliste NACH fmtStr */
vfprintf (ofile, fmtStr, arg_p);
va_end (arg_p);
fputs ("\n", ofile);}
char strEins[10];
char strZwei[10];
strcpy (strEins, "eins");
strcpy (strZwei, "zwei");
/* h_logfile = vordefiniertes Filehandle, Öffnen war erfolgreich */
logMe (h_logfile, "Blubb %s %s", strEins, strZwei);
----
Toll. Nix Aufregendes.
Nehmen wir aber mal an, logMe() befände sich in einer kleinen Toolsammlung,
die würde ich unter GPL stellen.
Jetzt geht ein Anfänger her und programmiert __versehentlich__ analog:
logMe ( "Blubb %s %s", strHinz, strKunz);
Die Resultate sind unvorhersehbar!!
Im "isolierten" Test löste das Programm so einen GPF aus.
(Natürlich weiß ich, dass bei vernünftig eingestelltem Warnlevel da
Warnungen über "pasisng argument X ..." etc. kommen. Nehmen wir aber mal an,
der Jungprogrammierer sieht auch die grade irgendwie nicht...)
FRAGE:
Wie kann ich so etwas sauber abfangen?
(nich schlagen) Mit den internen Attributen der struct _iobuf in stdio.h hab
ich schon herumexperimentiert, da hab ich aber leider kein Kriterium
gefunden wie man das sinnvoll abfangen kann und z. B. vorher einen exit(0)
auslösen kann, bevor Schlimmeres passiert.
Abfrage von ofile auf NULL ging auch nicht.
Gibt's da noch einen anderen Trick?
-Andreas
Doch, sind sie: sind logMe() und der o.a. Testcode im selben Modul
untergebracht, wird es wie gewünscht funktionieren, aber:
> Im "isolierten" Test löste das Programm so einen GPF aus.
> (Natürlich weiß ich, dass bei vernünftig eingestelltem Warnlevel da
> Warnungen über "pasisng argument X ..." etc. kommen.
In diesem Beispiel nicht wirklich (oder sagen wir besser: nicht
notwendigerweise; s.u.).
> Nehmen wir aber mal
> an, der Jungprogrammierer sieht auch die grade irgendwie nicht...)
>
> FRAGE:
> Wie kann ich so etwas sauber abfangen?
Indem man den korrekten Prototyp von logMe() in eine Header-Datei
schreibt, und diese von allen Modulen #includen läßt, die diese
Funktion benutzen. Dadurch weiß der Compiler, daß er statt
"strEins" und "strZwei" "&strEins[0]" und "&strZwei[0]" übergeben
muß (ohne Header bzw. Prototyp weiß er das nur, wenn die Funktion
im selben Modul definiert ist, in der sie auch aufgerufen wird). Der
vielleicht nicht ganz offensichtliche Unterschied zwischen "strEins"
und "&strEins[0]", die ja beide die Adresse des ersten Zeichens des
Strings "strEins" angeben, besteht darin, daß ersteres die direkte,
letzteres die indirekte Adresse darstellt, oder anders ausgedrückt:
ersteres ist die String-Startadresse im Speicher, letzteres ein
Zeiger auf diese Adresse (sie belegt also zusätzlichen Speicherplatz).
Unterläßt der Compiler diese implizite Konvertierung, interpretiert
logMe() die ersten Zeichen in "strEins" als Adresse, und versucht
indirekt darüber zuzugreifen -- das führt dann entweder zu falschen
Ergebnissen oder zu einem Hardware-Trap.
> (nich schlagen) Mit den internen Attributen der struct _iobuf in stdio.h
> hab ich schon herumexperimentiert, da hab ich aber leider kein Kriterium
> gefunden wie man das sinnvoll abfangen kann und z. B. vorher einen exit(0)
> auslösen kann, bevor Schlimmeres passiert.
> Abfrage von ofile auf NULL ging auch nicht.
>
> Gibt's da noch einen anderen Trick?
"Tricks" sind für saubere Programmierung normalerweise nicht notwendig;
aber der GNU-C-Compiler bietet noch eine interessante Erweiterung über
den "__attribute__()"-Qualifier. Damit kann man z.B. angeben, daß eine
Funktion ihre Argumente wie "printf()" verarbeitet; der Compiler prüft
dann automatisch, ob Anzahl und Typ der Formatzeichen mit denen der
angegebenen Argumente übereinstimmen, und generiert ggf. Warnungen oder
auch Fehlermeldungen. Nettes Feature! :-)
mike
"Michael Schumacher" <mi...@gmx.de> wrote in message
news:3852539.N...@misc.albasani.net...
> "Tricks" sind für saubere Programmierung normalerweise nicht notwendig;
> aber der GNU-C-Compiler bietet noch eine interessante Erweiterung über
> den "__attribute__()"-Qualifier. Damit kann man z.B. angeben, daß eine
> Funktion ihre Argumente wie "printf()" verarbeitet; der Compiler prüft
> dann automatisch, ob Anzahl und Typ der Formatzeichen mit denen der
> angegebenen Argumente übereinstimmen, und generiert ggf. Warnungen oder
> auch Fehlermeldungen. Nettes Feature! :-)
Wunderhübsch - Danke! :)
Damit lässt sich doch was anfangen.
Hab hier ja tatsächlich GCC (mingw32 um genau zu sein); i. d. R. erwähne ich
das in dieser NG ungerner, da irgendwelche compilerspezifischer Kram hier
bekanntlich OT ist.
(ebensowenig sollte man z. B. Fragen zur "conio.h" stellen, die m.E. eine
Borland-Spezialität ist)
-Andreas
> "Michael Schumacher" <mi...@gmx.de> wrote in message
> news:3852539.N...@misc.albasani.net...
>
>> "Tricks" sind für saubere Programmierung normalerweise nicht notwendig;
>> aber der GNU-C-Compiler bietet noch eine interessante Erweiterung über
>> den "__attribute__()"-Qualifier. Damit kann man z.B. angeben, daß eine
>> Funktion ihre Argumente wie "printf()" verarbeitet; der Compiler prüft
>> dann automatisch, ob Anzahl und Typ der Formatzeichen mit denen der
>> angegebenen Argumente übereinstimmen, und generiert ggf. Warnungen oder
>> auch Fehlermeldungen. Nettes Feature! :-)
>
> Wunderhübsch - Danke! :)
> Damit lässt sich doch was anfangen.
> Hab hier ja tatsächlich GCC (mingw32 um genau zu sein); i. d. R. erwähne
> ich das in dieser NG ungerner, da irgendwelche compilerspezifischer Kram
> hier bekanntlich OT ist.
Ich sehe das etwas lockerer, denn die Sprache C muß man ja letztlich auch
anwenden, und dann kommen zwangsläufig C-Compiler-Spezialitäten ins Spiel.
Und /so/ überlaufen ist diese NG nun auch wieder nicht, als daß man nicht
auch mal "Meta-Diskussionen" führen könnte -- was in anderen NGs als ganz
natürlich akzeptiert wird. Wer freundlich zu einem halbwegs passenden
Thema fragt, hat auch eine freundliche, halbwegs passende Antwort verdient
(und sei es auch nur der nette Hinweis, daß geeignetere Ansprechpartner in
"de.foo.bar" anzutreffen sind). :-)
> (ebensowenig sollte man z. B. Fragen zur "conio.h" stellen, die m.E. eine
> Borland-Spezialität ist)
Das ist eher ein "Relikt" aus DOS-Zeiten, und hat zugegebenermaßen in
dieser NG nichts zu suchen, genau wie die Myriaden anderer APIs auch,
sofern es nicht wenigstens "einigermaßen" um C-spezifische Themen geht.
Allerdings gibt's ja auch keinerlei "Antwort-Pflicht"... ;-)
mike
[...]
> Jetzt geht ein Anf�nger her und programmiert __versehentlich__ analog:
>
> logMe ( "Blubb %s %s", strHinz, strKunz);
>
> Die Resultate sind unvorhersehbar!!
> Im "isolierten" Test l�ste das Programm so einen GPF aus.
Hmm ... na und? Man duerfte noch viel lustigere Effekte erzielen
koennen, wenn man von einem Auruf a la
logMe(strHinz, ofile, "Blubb %s %s", strKunz)
ausgeht. Compiler ueberpruefen deswegen Argument-Typen, damit solche
Verwechslungen schneller gefunden werden. Wenn jemand die ignoriert, aus
welchem Grund auch immer, selber Schuld. Das Microsoft anscheined (lt
Wikipedia) nicht imstande ist, sinnvoller auf solche Exception zu
reagieren, als mitzuteilen, das ein Problem aufgetreten waere, ist
eben Pech fuer Leute, die fuer eine solche Umgebung programmieren.