Könnte ein verkappter static assert sein, gibt auch noch ne Variante mit
nem ungültigen Arrayzugriff. Wenn die Bedingung nicht erfüllt ist knallt
es bereits beim Kompilieren. Hat man früher so gemacht mangels anderer
Möglichkeiten.
Neuere C-Varianten (C11) unterstützen das Schlüsselwort _Static_assert
Im obigen Fall hat wahrscheinlich jemand ein liebevoll handgepacktes
struct gebastelt und will sicherstellen daß auch in ferner Zukunft nicht
klammheimlich die Alignmentregeln sich ändern ohne daß es beim
Kompilieren schon lautstark knallt mit direktem Zaunpfahlwink darauf was
falsch ist (sizeof soll genau 850 sein oder irgendwas stimmt nicht).
Mit _Static_assert kann man auch noch schön ne Meldung ausgeben:
1
typedefstruct{
2
u32magic;
3
settings_outtype_toutput_type;
4
boolis_npn;
5
}settings_t;
6
7
_Static_assert(_Alignof(settings_t)>=4,"settings_t must be aligned by at least 4");
8
_Static_assert(sizeof(settings_t)%4==0,"settings_t size must be multiple of 4");
9
_Static_assert(sizeof(settings_outtype_t)==1,"enum size must be 1");
In Deinem Beispiel gibts halt eine vollkommen absurde Fehlermeldung aber
immerhin, es kompiliert nicht klammheimlich. Man hätte vielleicht noch
einen Kommentar dazuschreiben können warum das da steht und wo
vermutlich der Fehler zu suchen ist (der Programmierer hatte ein
schlechtes Gewissen und kannte die wackelige Stelle ganz genau sonst
hätte er diese Absicherung dort nicht errichtet) als Hinweis für
zukünftige Leser die diesen alten Trick nicht kennen.
Bernd K. schrieb:> Neuere C-Varianten (C11) unterstützen das Schlüsselwort _Static_assert
Da nix von C da steht:
in C++ heisst es: static_assert()
(in C11 gibt es ein gleichlautendes Marcro dafür).
mark schrieb:> ich teile im worst-case 1/0 ? und es wird eh nichts ausgeführt?
so schauts aus.. es wird nicht nur nichts ausgeführt,
der Code rennt in einen divisionby0 error
(der hoffentlich irgendwo behandelt wird)
ich halte die Zeile für mindestens unschön ehrlich gesagt..
wenn es um die Ausführung geht
reicht die zweite Hälfte völlig
1
if(sizeof(*parameter)==850){}
macht NULL Sinn,
ausser dass ein Fehlerfall ausgelöst wird falls sizeof NICHT 850 liefert
beim compilieren.
Aber das lässt sich mMn auch eleganter abfragen ..
ein crash test header zB der sich beim release einfach wieder entfernen
lässt
Aber naja so macht halt jeder anders :D
mark schrieb:> if (1 / ((sizeof(*parameter) == 850) ? 1 : 0)) {}
Totaler Schwachsinn, denn es gibt bei -Wall -Wextra "nur" eine Warnung,
und zur Laufzeit keinen Div0-Error, da wegoptimiert (auch ohne -O)
Kann auch nur dort stehen, wo Statements zugelassen sind, also bspw.
nicht außerhalb von Funktionen. static_assert() dagegen schon.
Wilhelm M. schrieb:> Kann auch nur dort stehen, wo Statements zugelassen sind, also bspw.> nicht außerhalb von Funktionen. static_assert() dagegen schon.
Dafür hat static_assert das umgekehrte Problem. Wenn man ein Macro hat,
und das soll ein Resultat liefern, aber man will darin mit static_assert
was prüfen, das geht nicht...
Daniel A. schrieb:> Wilhelm M. schrieb:>> Kann auch nur dort stehen, wo Statements zugelassen sind, also bspw.>> nicht außerhalb von Funktionen. static_assert() dagegen schon.>> Dafür hat static_assert das umgekehrte Problem. Wenn man ein Macro hat,> und das soll ein Resultat liefern, aber man will darin mit static_assert> was prüfen, das geht nicht...
Mach mal ein Beispiel bitte.
Bernd K. schrieb:> typedef char> static_assertion_bufer_size_wrong[(sizeof(buffer_descriptor_t)==8)?1:-1] ;
Der "Trick" ist zumindest in der Hinsicht besser, als dass er
funktioniert, und einen Compile-Zeit Fehler produziert und kein
Statement ist. Trotzdem ist seine Zeit seit C11 definitiv vorbei, und
sollte durch static_assert() ersetzt werden.
Wilhelm M. schrieb:> Daniel A. schrieb:>> Wilhelm M. schrieb:>>> Kann auch nur dort stehen, wo Statements zugelassen sind, also bspw.>>> nicht außerhalb von Funktionen. static_assert() dagegen schon.>>>> Dafür hat static_assert das umgekehrte Problem. Wenn man ein Macro hat,>> und das soll ein Resultat liefern, aber man will darin mit static_assert>> was prüfen, das geht nicht...>> Mach mal ein Beispiel bitte.
Sowas geht nicht:
1
#include<assert.h>
2
3
#define DEVIDE_EVEN_NUMBER_BY_TWO(X) \
4
( 0 ? static_assert((X)%2 == 0, "Must be an even number!") : X/2 )
5
6
intbla=DEVIDE_EVEN_NUMBER_BY_TWO(42);// Geht nicht: error: expected expression before ‘_Static_assert’
Mein use-case war damals zwar etwas anders, ich wollte einen Typecheck
für einer generischen linked list machen, aber das ging damals noch aus
ganz anderen Gründen nicht ohne Erweiterungen (typeof) in C, also hab
ichs gelassen. Bin seither schon einmal in die Falle getappt, als ich
bei etwas Refactoring nicht aufpasste...
Der trick mit dem negativen Array type sieht aber interessant aus.
Scheint auch mit compund literalen zu gehen:
1
#include<stdint.h>
2
3
#define DEVIDE_EVEN_NUMBER_BY_TWO(X) \
4
(0 ? (int)(intptr_t)(int[(X)%2?-1:1]){0} : X/2)
5
6
intbla=DEVIDE_EVEN_NUMBER_BY_TWO(42);// OK
7
intbla2=DEVIDE_EVEN_NUMBER_BY_TWO(43);// Fehler
Cool. Nur dass der Komma Operator hier nicht anwendbar ist, ist etwas
schade. Und jetzt muss ich mir mein Listenmakroproblem wieder anschauen,
ob das nicht doch irgendwie geht...
Daniel A. schrieb:> Sowas geht nicht:#include <assert.h>>> #define DEVIDE_EVEN_NUMBER_BY_TWO(X) \> ( 0 ? static_assert((X)%2 == 0, "Must be an even number!") : X/2 )>> int bla = DEVIDE_EVEN_NUMBER_BY_TWO(42); // Geht nicht: error: expected> expression before ‘_Static_assert’
Ja, denn static_assert() ist kein Ausdruck.
Wenn ich Dich richtig verstehe, möchtest Du eine Zusicherung, die
1) in einem compile-time-constant Kontext eine compile-time Assertion
ist,
2) sonst eine run-time Assertion ist.
Könnte man so machen (in C++)
1
#include<cstdint>
2
#include<cassert>
3
4
constexprintdivEven(intv){
5
boolc=(v%2)==0;
6
assert(c);
7
returnc/2;
8
}
9
10
intmain(){
11
constexprautoe1=divEven(43);// compile-time-error
12
autoe2=divEven(43);// run-time-error
13
}
Fall 2) ist ja klar.
Fall 1) produziert den gewünschten compile-time Fehler, weil
__assert_fail(...) selbst nicht constexpr ist. Wird tatsächlich
desöfteren benutzt, finde ich aber auch nur einen Hack.
Für Fall 1) wäre ggf. eine andere Variante machbar:
1
template<autoV>
2
booldivEvenC(){
3
constexprboolc=(V%2)==0;
4
static_assert(c);
5
returnc/2;
6
7
}
8
9
intmain(){
10
constexprautoe3=divEvenC<43>();
11
autoe4=divEvenC<42>();
12
}
Noch eine Variante wäre, divEven() mit als
divEven(std::integral_constant<T, N>) zu überladen.
Wilhelm M. schrieb:> Wenn ich Dich richtig verstehe, möchtest Du eine Zusicherung, die>> 1) in einem compile-time-constant Kontext eine compile-time Assertion> ist,> 2) sonst eine run-time Assertion ist.
Nö, zur compile time zum compile-time-constant kontext reicht mir
völlig. Aber ich nutze eben C11, da gibts keine Templates und kein
constexpr, dafür muss ich dann Macros nehmen, und in gewissen
Situationen brauch ich dann halt ein Macro, das mir einen Wert zurück
gibt, den ich aber noch prüfen muss, weil man das Macro sonst falsch
anwenden könnte, und dann muss ich alles in eine Expression reinpacken,
und dann kann ich static_assert halt dort nicht mehr verwenden.
sid schrieb:> so schauts aus.. es wird nicht nur nichts ausgeführt,> der Code rennt in einen divisionby0 error> (der hoffentlich irgendwo behandelt wird)>> ich halte die Zeile für mindestens unschön ehrlich gesagt..> wenn es um die Ausführung geht> reicht die zweite Hälfte völligif(sizeof(*parameter) == 850){}>> macht NULL Sinn,
Verstehe ich nicht. Der Compiler sieht 1/0 und soll nicht warnen?
Vielleicht muss er nicht, vielleicht geht's eleganter, aber es ist doch
absurd, anzunehmen, dass der dortige Compiler nicht warnt.
Noch absurder ist es, das zu verbessern und dann beklagen dass das
keinen Sinn mehr macht.
Und das z.b. die Array-Version zuverlässiger und universeller ist:
geschenkt. Ich kannte die aber auch nicht von Anfang an.
A. S. schrieb:> Verstehe ich nicht. Der Compiler sieht 1/0 und soll nicht warnen?> Vielleicht muss er nicht, vielleicht geht's eleganter, aber es ist doch> absurd, anzunehmen, dass der dortige Compiler nicht warnt.
Der compiler schmeisst (hoffentlich) n Fehler aus und warnt nicht nur
(Warnungen könnten ja ignoriert werden)
Ja, das sieht aber in der Tat so aus (im nachhinein) als meinte ich die
vereinfachte if-kondition.
Hab ich vielleicht doof formuliert..
Stell dir ein
"So wie du sie im Code gefunden hast ..." davor vor :D
Denn was ich meinte ist,
dass es NULL Sinn macht die 'Fehlerquelle' absichtlich
in die if-Kondition zu packen die (wie ich annehme) Laufzeitrelevant
ist.
also im kompilierten Zustand immer und immer wieder abgefragt wird.
Nur um das kompilieren zu vermeiden.
mMn ist es sinnvoller das in einen header zu stecken den man bei
erfolgreichem Test auskommentieren kann um sauberere und besser lesbaren
Quellcode zu haben.
sid schrieb:> Denn was ich meinte ist,> dass es NULL Sinn macht die 'Fehlerquelle' absichtlich> in die if-Kondition zu packen die (wie ich annehme) Laufzeitrelevant> ist.> also im kompilierten Zustand immer und immer wieder abgefragt wird.> Nur um das kompilieren zu vermeiden.
ich würde annahmen, der TO hat den vollständigen Code gepostet. Also
eine Leere Schleife mit dieser if-Abfrage, die vom Compiler (oder wem
auch immer) komplett entfernt wird.
Aber klar, ein define, dass dann einfach nur "sAssert(850 == sizeof
*parameter);" erlaubt, wäre auch vor C11 schöner. Nur wie gesagt, dass
war vor Jahren nicht Standard. Ich habe es auch erst vor ~15 Jahren
irgendwo zufällig kennengelernt (mit []), als erster unter uns Kollegen.
Wenn das jemand selbst erdacht hat: Alle Achtung.
Writer schrieb:> ich würde annahmen, der TO hat den vollständigen Code gepostet. Also> eine Leere Schleife mit dieser if-Abfrage, die vom Compiler (oder wem> auch immer) komplett entfernt wird.
Ah siehste.. das hab ich anders gedeutet..
dann natürlich spielt es wirklich keine Rolle (wird ja
wegrationalisiert)
Aber so ist das halt..
am Ende des Tages erkennt man Programmierer and ihrem Dialekt wieder ;)