-Wformat und besonders -Wformat-security sind ja nicht verkehrt. Ein nicht-konstanter format string wird dann angemeckert. Seht gut, aber es gibt eine Grauzone, zum Beispiel finde ich, dass diese format strings durchaus konstant sind. Kann ich dem gcc außer "const" noch einen Tipp geben?
Im nächsten Beispiel ist im Endeffekt auch alles konstant, aber da ist die Warnung wohl unvermeidlich. Gibt es vielleicht "eine lib", mit der ich den format string prüfen könnte? Und wie sage ich dann dem strftime(), dass der ok ist?
Ja, natürlich kann ich das mount auch anders formulieren, da gibt es nur vier bekannte Dateisysteme. Aber wie man ein Datum schreibt, ist ja leider völlig undefiniert.
zum Beispiel finde ich, dass diese format strings durchaus
konstant sind. Kann ich dem gcc außer "const" noch einen Tipp
geben?
Damit ein Format-String gecheckt werden kann, muss er natürlich zur Compilezeit bekannt sein, und das ist
1
>constchar*fsopts=opttab[type];
Nun mal nicht, weil type nicht bekannt ist zur Laufzeit.
Ich nehme mal an, dass die Obfuskation über das Array nicht super Performance-kritisch ist, also einfach die 3 Fälle per if+else oder switch+case abhandeln mit FMT-Strings die zur Compilezeit bekannt sind.
Damit ein Format-String gecheckt werden kann, muss er natürlich zur
Compilezeit bekannt sein, und das ist
const char *fsopts = opttab[type];
Nun mal nicht, weil type nicht bekannt ist zur Laufzeit.
Ach was, natürlich ist type bekannt ;) Wenn es zu groß würde, wäre das ja undefined! Aber an der Stelle geht if/else problemlos, also gut.
Und jetzt auf einmal geht's für das Datumsformat genauso einfach: ich erlaube nur den Default oder %x "The preferred date representation for the current locale without the time". Wer sich ein Fantasieformat ausdenkt, oder in Italien die norwegische Schreibweise will, bekommt automatisch RFC 3339. Das muss reichen, manche Formate gehören sowieso verboten.
Haben wir wieder mal ein Problem elegant? umgangen. Trotzdem, so eine Format-Prüf-Funktion sollte es eigentlich geben, braucht man das nicht, wenn man gettext mit fremden Übersetzungen benutzt?
Ach, keiner versteht mich :( Natürlich ist das erst zur Laufzeit bekannt. Aber sonst heißt es immer, UB gibt es nicht. Also könnte der gcc sagen, es muss eins von den drei Formaten sein und die sind alle ok. Ich benutze allerdings auch -O, vielleicht würde er es mit -O3 sogar finden.
Ach, keiner versteht mich :( Natürlich ist das erst zur Laufzeit
bekannt. Aber sonst heißt es immer, UB gibt es nicht. Also könnte der
gcc sagen, es muss eins von den drei Formaten sein und die sind alle ok.
Das könnte er möglicherweise (Wo type herkommt und wie es zu seinem Wert kommt, sieht man deinem Code oben nicht), aber das wäre recht komplex, und so ein Verhalten müsste extra da reinprogrammiert werden, für einen äußerst seltenen Anwendungsfall.
Ich benutze allerdings auch -O, vielleicht würde er es mit -O3 sogar
finden.
Höhere Optimierungsstufen sind für sowas definitv besser, weil der Compiler dann eine ausführliche Codeanalyse machen muss, durch die solche Sonderfälle eher gefunden werden können.
Da type nur die Werte 0, 1, 2 annehmen kann, mache einen switch über die Variable type und schreibe das printf jedesmal explizit mit dem konkreten Format-String hin.
Dann kannst Du Dir das array "opttab" sparen und der Code wird lesbarer. Außerdem kann der Compiler dann zur Compilezeit die drei Formatstrings prüfen.
mache einen switch über die
Variable type und schreibe das printf jedesmal explizit mit dem
konkreten Format-String hin.
Ja, natürlich ist das in diesem Fall besser. Rein optisch sieht es jetzt garnicht so übel aus. Aber wenn es mehr Fälle werden, ist mir ein Liste mit structs (hier fstype und options) doch lieber.
Aber das ist Geschmackssache. Bei den heutigen Monitorgrößen muss man aber nicht unbedingt mit Platz geizen. Noch ein Vorteil: Ich kann mit dem Editor jederzeit einen else-if-Block zeilenweise rausschneiden oder einfügen, ohne die Formatierung in unmittelbarer Umgebung anpassen zu müssen.
Das war ja klar :) Aber so geht es natürlich auch nicht. Euch fehlen ein paar { { {. Entweder elif (oder so) oder die Klammern müssen sein. Spart ihr die { auch beim einzelnen if oder for mit nur einem Statement? Das ist ja nun total illegal
;)
Nein. Zu else if gibt es einen breiten Konsens, dass nur hier auf {} verzichtet werden darf, ja sogar sollte. Dafür ist das abschließende else Pflicht.
Die Klammern würden hier obfuskieren. Die anweisungsblöcke hingegen haben auch hier Klammern, egal ob 0, 1 oder mehr Anweisungen.
Nein. Zu else if gibt es einen breiten Konsens, dass nur hier auf {}
verzichtet werden darf. Dafür ist das abschließende else Pflicht.
Ach wo, wenn es legal ist darf man es schreiben. Ich habe auch schon so Sachen wie "do if(){ }while();" oder "if(){}else for(;;){}" hingeschrieben. Das ist völlig OK.
Immerhin werfen gcc und Clang inzwischen eine Warnung, wenn die auf else
ohne Klammern und potentiell missverständliche Formatierungen treffen.
Das ist ja auch sinnvoll. Aber hier wird garantiert nicht gewarnt:
1
if(foo)
2
{
3
bar();
4
}
5
elseif(foo2)
6
{
7
bar2();
8
}
9
elseif(foo3)
10
{
11
bar3();
12
}
13
else
14
{
15
baz();
16
}
Grund: Das auf else folgende if() mit geklammerten Block dahinter ist für den Compiler grundsätzlich ein Statement, so dass auf die geschweifte Klammer zwischen else und if immer(!) verzichtet werden kann - wie man es vom switch() gewohnt ist. Das ist auch keine C-Sonderregel oder ähnliches, sondern ergibt sich klar aus der C-Grammatik.
Auf diese Klammer- bzw. Einrückungs-Orgie hier:
1
if(foo)
2
{
3
bar();
4
}
5
else
6
{
7
if(foo2)
8
{
9
bar2();
10
}
11
else
12
{
13
if(foo3)
14
{
15
bar3();
16
}
17
else
18
{
19
baz();
20
}
21
}
22
}
kann also immer verzichtet werden. Es reicht eine lineare Aufzählung aller Bedingungen. Die obere lineare Lösung ist auch wesentlich lesbarer als ein derart ineinander geschachtelter Block. Der wird nämlich, wenn eine neue Bedingung hinzukommt, immer weiter verschachtelt und nach rechts immer weiter eingerückt. Bei 20 Bedingungen ist man dann "ganz weit draußen".
Immerhin werfen gcc und Clang inzwischen eine Warnung, wenn die auf else
ohne Klammern und potentiell missverständliche Formatierungen treffen.
Wirklich bei else if -Reihen mit abschließendem else? (Ich nehme an, Du hast das ausprobiert und mit MISRA und Co bisher nichts zu tun gehabt. Da ist dann wohl was schiefgelaufen)
Oh Gott, jetzt auch noch MISRA. Das ist nun wirklich nur noch verschwendete Arbeitszeit und herausgeworfenes Geld.
Wer glaubt solche stumpfsinnige generelle Einschränkungen brächten irgendwas, sollte gleich Rust nehmen.