Was ist der beste Weg, um statische Zusicherungen zur Kompilierungszeit in C (nicht in C ++) zu erzielen, wobei der Schwerpunkt auf GCC liegt?
Was ist der beste Weg, um statische Zusicherungen zur Kompilierungszeit in C (nicht in C ++) zu erzielen, wobei der Schwerpunkt auf GCC liegt?
Antworten:
Der C11-Standard fügt das _Static_assert
Schlüsselwort hinzu.
Dies ist seit gcc-4.6 implementiert :
_Static_assert (0, "assert1"); /* { dg-error "static assertion failed: \"assert1\"" } */
Der erste Slot muss ein integraler konstanter Ausdruck sein. Der zweite Slot ist ein konstantes String-Literal, das lang sein kann ( _Static_assert(0, L"assertion of doom!")
).
Ich sollte beachten, dass dies auch in neueren Versionen von clang implementiert ist.
error: expected declaration specifiers or '...' before 'sizeof'
für Zeile bekomme static_assert( sizeof(int) == sizeof(long int), "Error!);
(ich benutze übrigens C, nicht C ++)
_Static_assert( sizeof(int) == sizeof(long int), "Error!");
Auf meinem Macine wird der Fehler angezeigt.
error: expected declaration specifiers or '...' before 'sizeof'
AND error: expected declaration specifiers or '...' before string constant
(er bezieht sich auf die "Error!"
Zeichenfolge) (auch: Ich kompiliere mit -std = c11. Wenn die Deklaration in eine Funktion eingefügt wird, funktioniert alles gut (schlägt fehl und ist wie erwartet erfolgreich))
_Static_assert
nicht den C ++ - Standard static_assert
. Sie müssen `#include <assert.h> verwenden, um das static_assert-Makro abzurufen.
Dies funktioniert im Funktions- und Nichtfunktionsbereich (jedoch nicht innerhalb von Strukturen, Gewerkschaften).
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]
STATIC_ASSERT(1,this_should_be_true);
int main()
{
STATIC_ASSERT(1,this_should_be_true);
}
Wenn die Zusicherung der Kompilierungszeit nicht übereinstimmen konnte, wird von GCC eine fast verständliche Nachricht generiert sas.c:4: error: size of array ‘static_assertion_this_should_be_true’ is negative
Das Makro könnte oder sollte geändert werden, um einen eindeutigen Namen für das typedef zu generieren (dh __LINE__
am Ende des static_assert_...
Namens verketten )
Anstelle eines ternären kann auch dieser verwendet werden, #define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[2*(!!(COND))-1]
der sogar auf dem rostigen alten cc65-Compiler (für den 6502-CPU) funktioniert.
UPDATE: Der
Vollständigkeit halber hier die Version mit__LINE__
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(!!(COND))*2-1]
// token pasting madness:
#define COMPILE_TIME_ASSERT3(X,L) STATIC_ASSERT(X,static_assertion_at_line_##L)
#define COMPILE_TIME_ASSERT2(X,L) COMPILE_TIME_ASSERT3(X,L)
#define COMPILE_TIME_ASSERT(X) COMPILE_TIME_ASSERT2(X,__LINE__)
COMPILE_TIME_ASSERT(sizeof(long)==8);
int main()
{
COMPILE_TIME_ASSERT(sizeof(int)==4);
}
UPDATE2: GCC-spezifischer Code
GCC 4.3 (ich denke) hat die Funktionsattribute "Fehler" und "Warnung" eingeführt. Wenn ein Aufruf einer Funktion mit diesem Attribut nicht durch Eliminierung des toten Codes (oder andere Maßnahmen) beseitigt werden konnte, wird ein Fehler oder eine Warnung generiert. Dies kann verwendet werden, um Assets zur Kompilierungszeit mit benutzerdefinierten Fehlerbeschreibungen zu erstellen. Es bleibt zu bestimmen, wie sie im Namespace-Bereich verwendet werden können, ohne auf eine Dummy-Funktion zurückzugreifen:
#define CTC(X) ({ extern int __attribute__((error("assertion failure: '" #X "' not true"))) compile_time_check(); ((X)?0:compile_time_check()),0; })
// never to be called.
static void my_constraints()
{
CTC(sizeof(long)==8);
CTC(sizeof(int)==4);
}
int main()
{
}
Und so sieht es aus:
$ gcc-mp-4.5 -m32 sas.c
sas.c: In function 'myc':
sas.c:7:1: error: call to 'compile_time_check' declared with attribute error: assertion failure: `sizeof(int)==4` not true
-Og
) reicht jedoch häufig aus, damit dies funktioniert, und sollte das Debuggen nicht beeinträchtigen. Man kann in Betracht ziehen, die statische Zusicherung zu einer No-Op- oder Laufzeit-Zusicherung zu machen, wenn __OPTIMIZE__
(und __GNUC__
) nicht definiert ist.
__LINE__
Version in gcc 4.1.1 ... mit gelegentlichem Ärger, wenn zwei verschiedene Header zufällig einen in derselben nummerierten Zeile haben!
Ich weiß, dass in der Frage gcc ausdrücklich erwähnt wird, aber der Vollständigkeit halber ist hier eine Optimierung für Microsoft-Compiler.
Die Verwendung des negativ dimensionierten Arrays typedef überzeugt cl nicht , einen anständigen Fehler auszuspucken. Es heißt nur error C2118: negative subscript
. Ein Bitfeld mit einer Breite von Null ist in dieser Hinsicht besser. Da dies das Typendeffing einer Struktur beinhaltet, müssen wir wirklich eindeutige Typnamen verwenden. __LINE__
schneidet den Senf nicht - es ist möglich, dass COMPILE_TIME_ASSERT()
in einem Header und einer Quelldatei ein in derselben Zeile steht, und Ihre Kompilierung wird unterbrochen. __COUNTER__
kommt zur Rettung (und es ist in gcc seit 4.3).
#define CTASTR2(pre,post) pre ## post
#define CTASTR(pre,post) CTASTR2(pre,post)
#define STATIC_ASSERT(cond,msg) \
typedef struct { int CTASTR(static_assertion_failed_,msg) : !!(cond); } \
CTASTR(static_assertion_failed_,__COUNTER__)
Jetzt
STATIC_ASSERT(sizeof(long)==7, use_another_compiler_luke)
unter cl
gibt:
Fehler C2149: 'static_assertion_failed_use_another_compiler_luke': Das benannte Bitfeld darf keine Breite von Null haben
Gcc gibt auch eine verständliche Nachricht:
Fehler: Nullbreite für Bitfeld 'static_assertion_failed_use_another_compiler_luke'
Aus Wikipedia :
#define COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;}
COMPILE_TIME_ASSERT( BOOLEAN CONDITION );
Ich würde NICHT empfehlen, die Lösung mit einem zu verwenden typedef
:
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]
Es typedef
wird NICHT garantiert, dass die Array-Deklaration mit dem Schlüsselwort zur Kompilierungszeit ausgewertet wird. Beispielsweise wird der folgende Code im Blockbereich kompiliert:
int invalid_value = 0;
STATIC_ASSERT(invalid_value, this_should_fail_at_compile_time_but_will_not);
Ich würde dies stattdessen empfehlen (auf C99):
#define STATIC_ASSERT(COND,MSG) static int static_assertion_##MSG[(COND)?1:-1]
Aufgrund des static
Schlüsselworts wird das Array zur Kompilierungszeit definiert. Beachten Sie, dass diese Zusicherung nur funktioniert, mit COND
denen zur Kompilierungszeit ausgewertet wird. Es funktioniert nicht mit Bedingungen (dh die Kompilierung schlägt fehl) mit Bedingungen, die auf Werten im Speicher basieren, z. B. Werten, die Variablen zugewiesen sind.
Bei Verwendung des Makros STATIC_ASSERT () mit __LINE__
, können Sie Zeilennummernkonflikte zwischen einem Eintrag in einer .c-Datei und einem anderen Eintrag in einer Header-Datei vermeiden, indem Sie einschließen __INCLUDE_LEVEL__
.
Zum Beispiel :
/* Trickery to create a unique variable name */
#define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y )
#define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2( X, Y )
#define BOOST_DO_JOIN2( X, Y ) X##Y
#define STATIC_ASSERT(x) typedef char \
BOOST_JOIN( BOOST_JOIN(level_,__INCLUDE_LEVEL__), \
BOOST_JOIN(_assert_on_line_,__LINE__) ) [(x) ? 1 : -1]
Der klassische Weg ist die Verwendung eines Arrays:
char int_is_4_bytes_assertion[sizeof(int) == 4 ? 1 : -1];
Es funktioniert, weil wenn die Behauptung wahr ist, das Array die Größe 1 hat und gültig ist, aber wenn es falsch ist, gibt die Größe -1 einen Kompilierungsfehler aus.
Die meisten Compiler zeigen den Namen der Variablen an und zeigen auf den rechten Teil des Codes, wo Sie eventuelle Kommentare zur Zusicherung hinterlassen können.
#define STATIC_ASSERT()
allgemeinere Beispiele und Beispiel-Compiler-Ausgaben aus Ihren generischen Beispielen STATIC_ASSERT()
bereitstellen, erhalten Sie viel mehr Upvotes und diese Technik macht meiner Meinung nach mehr Sinn.
Von Perl, speziell perl.h
Zeile 3455 ( <assert.h>
ist vorher enthalten):
/* STATIC_ASSERT_DECL/STATIC_ASSERT_STMT are like assert(), but for compile
time invariants. That is, their argument must be a constant expression that
can be verified by the compiler. This expression can contain anything that's
known to the compiler, e.g. #define constants, enums, or sizeof (...). If
the expression evaluates to 0, compilation fails.
Because they generate no runtime code (i.e. their use is "free"), they're
always active, even under non-DEBUGGING builds.
STATIC_ASSERT_DECL expands to a declaration and is suitable for use at
file scope (outside of any function).
STATIC_ASSERT_STMT expands to a statement and is suitable for use inside a
function.
*/
#if (defined(static_assert) || (defined(__cplusplus) && __cplusplus >= 201103L)) && (!defined(__IBMC__) || __IBMC__ >= 1210)
/* static_assert is a macro defined in <assert.h> in C11 or a compiler
builtin in C++11. But IBM XL C V11 does not support _Static_assert, no
matter what <assert.h> says.
*/
# define STATIC_ASSERT_DECL(COND) static_assert(COND, #COND)
#else
/* We use a bit-field instead of an array because gcc accepts
'typedef char x[n]' where n is not a compile-time constant.
We want to enforce constantness.
*/
# define STATIC_ASSERT_2(COND, SUFFIX) \
typedef struct { \
unsigned int _static_assertion_failed_##SUFFIX : (COND) ? 1 : -1; \
} _static_assertion_failed_##SUFFIX PERL_UNUSED_DECL
# define STATIC_ASSERT_1(COND, SUFFIX) STATIC_ASSERT_2(COND, SUFFIX)
# define STATIC_ASSERT_DECL(COND) STATIC_ASSERT_1(COND, __LINE__)
#endif
/* We need this wrapper even in C11 because 'case X: static_assert(...);' is an
error (static_assert is a declaration, and only statements can have labels).
*/
#define STATIC_ASSERT_STMT(COND) STMT_START { STATIC_ASSERT_DECL(COND); } STMT_END
Wenn static_assert
verfügbar (von <assert.h>
), wird es verwendet. Andernfalls wird, wenn die Bedingung falsch ist, ein Bitfeld mit einer negativen Größe deklariert, wodurch die Kompilierung fehlschlägt.
STMT_START
/ STMT_END
sind Makros, die auf do
/ erweitert while (0)
werden.
_Static_assert()
ist jetzt in gcc für alle Versionen von C und definiert static_assert()
ist in C ++ 11 und höher definiertSTATIC_ASSERT()
funktioniert daher in:g++ -std=c++11
) oder höhergcc -std=c90
gcc -std=c99
gcc -std=c11
gcc
(kein Standard angegeben)Definieren Sie STATIC_ASSERT
wie folgt:
/* For C++: */
#ifdef __cplusplus
#ifndef _Static_assert
#define _Static_assert static_assert /* `static_assert` is part of C++11 or later */
#endif
#endif
/* Now for gcc (C) (and C++, given the define above): */
#define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")
Verwenden Sie es jetzt:
STATIC_ASSERT(1 > 2); // Output will look like: error: static assertion failed: "(1 > 2) failed"
Getestet in Ubuntu mit gcc 4.8.4:
Beispiel 1: Gute gcc
Ausgabe (dh: Die STATIC_ASSERT()
Codes funktionieren, aber die Bedingung war falsch und verursachte eine Bestätigung zur Kompilierungszeit):
$ gcc -Wall -o static_assert static_assert.c && ./static_assert
static_assert.c: In Funktion 'main'
static_assert.c: 78: 38: Fehler: statische Zusicherung fehlgeschlagen: "(1> 2) fehlgeschlagen"
#define STATIC_ASSERT (test_for_true ) _Static_assert ((test_for_true), "(" #test_for_true ") fehlgeschlagen")
^
static_assert.c: 88: 5: Hinweis: bei Erweiterung des Makros 'STATIC_ASSERT'
STATIC_ASSERT (1> 2);
^
Beispiel 2: Gute g++ -std=c++11
Ausgabe (dh: Die STATIC_ASSERT()
Codes funktionieren, aber die Bedingung war falsch und verursachte eine Bestätigung zur Kompilierungszeit):
$ g ++ -Wall -std = c ++ 11 -o static_assert static_assert.c && ./static_assert
static_assert.c: In Funktion 'int main ()'
static_assert.c: 74: 32: Fehler: statische Zusicherung fehlgeschlagen: (1> 2) fehlgeschlagen
#define _Static_assert static_assert / *static_assert
ist Teil von C ++ 11 oder höher * /
^
static_assert.c: 78: 38: Hinweis: in Erweiterung des Makros '_Static_assert'
#define STATIC_ASSERT (test_for_true) _Static_assert ((test_for_true), "(" #test_for_true ") failed")
^
static_assert.c: 88: 5: Hinweis: bei Erweiterung des Makros 'STATIC_ASSERT'
STATIC_ASSERT (1> 2);
^
Beispiel 3: Fehlgeschlagene C ++ - Ausgabe (dh: Der Assert-Code funktioniert überhaupt nicht richtig, da hierfür eine Version von C ++ vor C ++ 11 verwendet wird):
$ g ++ -Wall -o static_assert static_assert.c && ./static_assert
static_assert.c: 88: 5: Warnung: Bezeichner 'static_assert' ist ein Schlüsselwort in C ++ 11 [-Wc ++ 0x-kompatibel]
STATIC_ASSERT (1> 2 );
^
static_assert.c: In der Funktion 'int main ()'
static_assert.c: 78: 99: Fehler: 'static_assert' wurde in diesem Bereich nicht deklariert
#define STATIC_ASSERT (test_for_true) _Static_assert ((test_for_true), "(" #test_for_true ") ) fehlgeschlagen ")
^
static_assert.c: 88: 5: Hinweis: bei Erweiterung des Makros 'STATIC_ASSERT'
STATIC_ASSERT (1> 2);
^
/*
static_assert.c
- test static asserts in C and C++ using gcc compiler
Gabriel Staples
4 Mar. 2019
To be posted in:
1. /programming/987684/does-gcc-have-a-built-in-compile-time-assert/987756#987756
2. /programming/3385515/static-assert-in-c/7287341#7287341
To compile & run:
C:
gcc -Wall -o static_assert static_assert.c && ./static_assert
gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert
gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert
gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert
C++:
g++ -Wall -o static_assert static_assert.c && ./static_assert
g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert
g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert
g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert
-------------
TEST RESULTS:
-------------
1. `_Static_assert(false, "1. that was false");` works in:
C:
gcc -Wall -o static_assert static_assert.c && ./static_assert YES
gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert YES
gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert YES
gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert YES
C++:
g++ -Wall -o static_assert static_assert.c && ./static_assert NO
g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert NO
g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert NO
g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert NO
2. `static_assert(false, "2. that was false");` works in:
C:
gcc -Wall -o static_assert static_assert.c && ./static_assert NO
gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert NO
gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert NO
gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert NO
C++:
g++ -Wall -o static_assert static_assert.c && ./static_assert NO
g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert NO
g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert NO
g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert YES
3. `STATIC_ASSERT(1 > 2);` works in:
C:
gcc -Wall -o static_assert static_assert.c && ./static_assert YES
gcc -Wall -std=c90 -o static_assert static_assert.c && ./static_assert YES
gcc -Wall -std=c99 -o static_assert static_assert.c && ./static_assert YES
gcc -Wall -std=c11 -o static_assert static_assert.c && ./static_assert YES
C++:
g++ -Wall -o static_assert static_assert.c && ./static_assert NO
g++ -Wall -std=c++98 -o static_assert static_assert.c && ./static_assert NO
g++ -Wall -std=c++03 -o static_assert static_assert.c && ./static_assert NO
g++ -Wall -std=c++11 -o static_assert static_assert.c && ./static_assert YES
*/
#include <stdio.h>
#include <stdbool.h>
/* For C++: */
#ifdef __cplusplus
#ifndef _Static_assert
#define _Static_assert static_assert /* `static_assert` is part of C++11 or later */
#endif
#endif
/* Now for gcc (C) (and C++, given the define above): */
#define STATIC_ASSERT(test_for_true) _Static_assert((test_for_true), "(" #test_for_true ") failed")
int main(void)
{
printf("Hello World\n");
/*_Static_assert(false, "1. that was false");*/
/*static_assert(false, "2. that was false");*/
STATIC_ASSERT(1 > 2);
return 0;
}
static_assert
Makro drin ist assert.h
?
static_assert()
ist es in C überhaupt nicht verfügbar. Siehe auch hier: en.cppreference.com/w/cpp/language/static_assert - es zeigt static_assert
, dass "(seit C ++ 11)" vorhanden ist. Das Schöne an meiner Antwort ist, dass es in gccs C90 und höher sowie in C ++ 11 und höher funktioniert, anstatt nur in C ++ 11 und höher static_assert()
. Was ist an meiner Antwort kompliziert? Es sind nur ein paar #define
s.
static_assert
ist in C seit C11 definiert. Es ist ein Makro, das erweitert wird _Static_assert
. en.cppreference.com/w/c/error/static_assert . Zusätzlich und im Gegensatz zu Ihrer Antwort _Static_assert
ist in c99 und c90 in gcc nicht verfügbar (nur in gnu99 und gnu90). Dies entspricht dem Standard. Grundsätzlich erledigen Sie eine Menge zusätzlicher Arbeit, die nur dann Vorteile bringt, wenn sie mit gnu90 und gnu99 kompiliert wird, und die den tatsächlichen Anwendungsfall unbedeutend klein macht.
Für diejenigen unter Ihnen, die etwas wirklich Grundlegendes und Tragbares wollen, aber keinen Zugriff auf C ++ 11-Funktionen haben, habe ich genau das Richtige geschrieben.
Verwenden STATIC_ASSERT
Sie es normal (Sie können es zweimal in derselben Funktion schreiben, wenn Sie möchten) und verwenden Sie es GLOBAL_STATIC_ASSERT
außerhalb von Funktionen mit einer eindeutigen Phrase als erstem Parameter.
#if defined(static_assert)
# define STATIC_ASSERT static_assert
# define GLOBAL_STATIC_ASSERT(a, b, c) static_assert(b, c)
#else
# define STATIC_ASSERT(pred, explanation); {char assert[1/(pred)];(void)assert;}
# define GLOBAL_STATIC_ASSERT(unique, pred, explanation); namespace ASSERTATION {char unique[1/(pred)];}
#endif
GLOBAL_STATIC_ASSERT(first, 1, "Hi");
GLOBAL_STATIC_ASSERT(second, 1, "Hi");
int main(int c, char** v) {
(void)c; (void)v;
STATIC_ASSERT(1 > 0, "yo");
STATIC_ASSERT(1 > 0, "yo");
// STATIC_ASSERT(1 > 2, "yo"); //would compile until you uncomment this one
return 0;
}
Erläuterung:
Zuerst wird geprüft, ob Sie die echte Zusicherung haben, die Sie definitiv verwenden möchten, wenn sie verfügbar ist.
Wenn Sie dies nicht tun, wird es pred
bestätigt, indem Sie Ihr Eis erhalten und es durch sich selbst teilen. Dies macht zwei Dinge.
Wenn es Null ist, id est, ist die Zusicherung fehlgeschlagen, führt dies zu einem Fehler beim Teilen durch Null (die Arithmetik wird erzwungen, weil versucht wird, ein Array zu deklarieren).
Wenn es nicht Null ist, normalisiert es die Arraygröße auf 1
. Wenn die Behauptung bestanden wurde, möchten Sie nicht, dass sie trotzdem fehlschlägt, da Ihr Prädikat als -1
(ungültig) oder 232442
(massive Platzverschwendung, IDK, wenn es optimiert würde) bewertet wird.
Da STATIC_ASSERT
es in geschweifte Klammern gesetzt ist, ist es ein Block, der die Variable abdecktassert
Das heißt, Sie können es viele Male schreiben.
Es wirft es auch aufvoid
Dies ist ein bekannter Weg, um unused variable
Warnungen loszuwerden .
Für GLOBAL_STATIC_ASSERT
statt in einem Codeblock zu sein, erzeugt er einen Namespace. Namespaces sind außerhalb von Funktionen zulässig. Ein unique
Bezeichner ist erforderlich, um widersprüchliche Definitionen zu stoppen, wenn Sie diese mehrmals verwenden.
Arbeitete für mich an GCC und VS'12 C ++
Dies funktioniert mit dem Optionssatz "Nicht verwendete entfernen". Ich kann eine globale Funktion verwenden, um globale Parameter zu überprüfen.
//
#ifndef __sassert_h__
#define __sassert_h__
#define _cat(x, y) x##y
#define _sassert(exp, ln) \
extern void _cat(ASSERT_WARNING_, ln)(void); \
if(!(exp)) \
{ \
_cat(ASSERT_WARNING_, ln)(); \
}
#define sassert(exp) _sassert(exp, __LINE__)
#endif //__sassert_h__
//-----------------------------------------
static bool tab_req_set_relay(char *p_packet)
{
sassert(TXB_TX_PKT_SIZE < 3000000);
sassert(TXB_TX_PKT_SIZE >= 3000000);
...
}
//-----------------------------------------
Building target: ntank_app.elf
Invoking: Cross ARM C Linker
arm-none-eabi-gcc ...
../Sources/host_if/tab_if.c:637: undefined reference to `ASSERT_WARNING_637'
collect2: error: ld returned 1 exit status
make: *** [ntank_app.elf] Error 1
//
Dies funktionierte für einige alte gcc. Entschuldigung, dass ich vergessen habe, um welche Version es sich handelt:
#define _cat(x, y) x##y
#define _sassert(exp, ln)\
extern char _cat(SASSERT_, ln)[1]; \
extern char _cat(SASSERT_, ln)[exp ? 1 : 2]
#define sassert(exp) _sassert((exp), __LINE__)
//
sassert(1 == 2);
//
#148 declaration is incompatible with "char SASSERT_134[1]" (declared at line 134) main.c /test/source/controller line 134 C/C++ Problem
_Static_assert
Teil des C11-Standards ist und jeder Compiler, der C11 unterstützt, es haben wird.