

Die am stärksten überbindete C ++-Assertion-Bibliothek
Bibliotheksphilosophie: Bieten Sie möglichst hilfreiche diagnostische Informationen wie möglich.
Einige der großartigen Dinge, die die Bibliothek tut:
void zoog ( const std::map<std::string, int >& map) {
DEBUG_ASSERT (map. contains ( " foo " ), " expected key not found " , map);
}
ASSERT (vec.size() > min_items(), "vector doesn't have enough items", vec);
std::optional< float > get_param ();
float f = * ASSERT_VAL (get_param());
Arten von Behauptungen:
Bedingte Behauptungen:
DEBUG_ASSERT : In Debug überprüft, aber nichts in der Freigabe (analog zum assert der Standardbibliothek)ASSERT : Sowohl im Debug- als auch in der Veröffentlichung eingechecktASSUME : In Debug eincheckt und dient als Optimierungshinweise in der VeröffentlichungBedingungslose Behauptungen:
PANIC : Auslöser sowohl im Debuggen als auch in der VeröffentlichungUNREACHABLE : Auslöser im Debug, die in der Veröffentlichung als unerreichbar markiert werden Bevorzugen Sie eine niedrige assert ?
Sie können das Kleinbuchstaben debug_assert aktivieren und Aliase mit -DLIBASSERT_LOWERCASE assert .
Zusammenfassung der Funktionen:
ASSERT_EQ usw.DEBUG_ASSERT_VAL und ASSERT_VAL varianten, die einen Wert zurückgeben, damit sie nahtlos in Code integriert werden können, z. B. FILE* f = ASSERT_VAL(fopen(path, "r") != nullptr) include (FetchContent)
FetchContent_Declare(
libassert
GIT_REPOSITORY https://github.com/jeremy-rifkin/libassert.git
GIT_TAG v2.1.2 # <HASH or TAG>
)
FetchContent_MakeAvailable(libassert)
target_link_libraries (your_target libassert::assert)
# On windows copy libassert.dll to the same directory as the executable for your_target
if ( WIN32 )
add_custom_command (
TARGET your_target POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:libassert::assert>
$<TARGET_FILE_DIR:your_target>
)
endif () Stellen Sie sicher, dass Sie mit -DCMAKE_BUILD_TYPE=Debug oder -DDCMAKE_BUILD_TYPE=RelWithDebInfo für Symbole und Zeileninformationen konfigurieren.
Auf macOS wird empfohlen, eine .dsym -Datei zu generieren, siehe Plattform Logistics unten.
Weitere Möglichkeiten, die Bibliothek zu verwenden, z. B. über Paketmanager oder eine systemweite Installation, siehe Verwendung unten.
Grundsätzlich besteht die Aufgabe von Behauptungen darin, Annahmen in Software zu überprüfen und Verstöße in der Nähe ihrer Quellen zu identifizieren. Assertion -Tools sollte dem Entwickler so viele Informationen und Kontext für die Bereitstellung von so vielen Kontext wie möglich priorisieren, um eine schnelle Triage zu ermöglichen. Leider bietet vorhandene Instrumente für Sprach- und Bibliothek nur sehr begrenzte Triage -Informationen.
Zum Beispiel mit stdlib behauptet eine Behauptung wie assert(n <= 12); Bietet keine Informationen über das Scheitern darüber, warum es fehlgeschlagen ist oder was zu seinem Versagen führte. Die Bereitstellung einer Stapelspur und dem Wert von n Greatley verbessert die Triage und das Debuggen. Im Idealfall sollte ein Behauptungsversagen genügend diagnostische Informationen liefern, die der Programm nicht in einem Debugger wiedergeben muss, um das Problem zu bestimmen.
Version 1 dieser Bibliothek war eine Erkundung, in der untersucht wurde, wie viel hilfreiche Informationen und Funktionen in Behauptungen gepackt werden konnten und gleichzeitig eine schnelle und einfache Schnittstelle für den Entwickler bereitstellen.
Version 2 dieser Bibliothek nimmt aus Version 1 Unterricht, um ein Tool zu erstellen, das ich persönlich in der Entwicklung unverzichtbar empfunden habe.
Das wichtigste Merkmal, das diese Bibliothek unterstützt, ist die automatische Ausdrucksabteilung. Keine Notwendigkeit für ASSERT_LT oder andere Probleme, assert(vec.size() > 10); wird automatisch verstanden, wie oben gezeigt.
Werte, die an Assert -Ausdrücken beteiligt sind, werden angezeigt. Redundante Diagnose wie 2 => 2 werden vermieden.
DEBUG_ASSERT (map.count( 1 ) == 2);
Nur der vollständige Assert -Ausdruck kann aus einem Makroaufruf extrahiert werden. Das Zeigen, welche Teile des Ausdrucks entsprechen, welche Werte eine grundlegende Ausdrucksanalyse erfordert. Die C ++ - Grammatik ist mehrdeutig, aber die meisten Ausdrücke können disambiguiert werden.
Alle Behauptungen in dieser Bibliothek unterstützen optionale diagnostische Nachrichten sowie willkürliche andere diagnostische Nachrichten.
FILE* f = ASSERT_VAL(fopen(path, " r " ) != nullptr , " Internal error with foobars " , errno, path); Für errno wird eine spezielle Handhabung bereitgestellt, und Strerror wird automatisch aufgerufen.
HINWEIS: Zusätzliche Diagnostik werden nur im Fehlerpfad einer Behauptung bewertet.

Es wurde viel Arbeit in die Erzeugung von hübschen Stapelspuren und die Formatierung von ihnen so gut wie möglich gestellt. CPPTrace wird als tragbare und in sich geschlossene Lösung für Stacktraces Pre-C ++ 23 verwendet. Optionale Konfigurationen finden Sie in der Dokumentation der Bibliothek.
Eine bemerkenswerte Funktion ist, dass anstatt immer vollständige Pfade zu drucken, nur die Mindestanzahl der zur Unterscheidung von Pfaden benötigten Verzeichnissen gedruckt werden.

Ein weiteres Merkmal, das es wert ist, darauf hinzuweisen, ist, dass die Stapelspuren mit tiefem Rekursion Spuren falten:

Der Assertion -Handler wendet die Syntax hervor, wo immer angemessen in allen obigen Screenshots zu sehen sind. Dies soll die Lesbarkeit verbessern.
Libassert unterstützt maßgefertigte Behauptungsfehlerhandler:
void handler (assert_type type, const assertion_info& assertion) {
throw std::runtime_error ( " Assertion failed: n " + assertion. to_string ());
}
int main () {
libassert::set_failure_handler (handler);
} Es wird viel Sorgfalt für die Erzeugung von Debug -Zeichenfolgen von Werten so effektiv wie möglich gewährt: Zeichenfolgen, Zeichen, Zahlen sollten alle wie erwartet gedruckt werden. Zusätzlich werden Container, Tupel, Std :: optionale, intelligente Zeiger usw. alle angestrahlt, um so viele Informationen wie möglich anzuzeigen. Wenn ein benutzerdefinierter Typ operator<<(std::ostream& o, const S& s) , wird diese Überladung aufgerufen. Andernfalls wird eine Standardnachricht gedruckt. Zusätzlich wird ein Stringification -Anpassungspunkt bereitgestellt:
template <> struct libassert ::stringifier<MyObject> {
std::string stringify ( const MyObject& type) {
return ...;
}
};

Assertionswerte werden sowohl in Hex oder Binär als auch dezimal gedruckt, wenn hex/binär auf beiden Seiten eines Ausdrucks der Behauptung verwendet wird:
ASSERT (get_mask() == 0b00001101);
Da Ausdrücke bereits automatisch zersetzt werden, können Sie sich für die automatisch unterschriebene Vergleiche mit der Zeichensicherheit mit -DLIBASSERT_SAFE_COMPARISONS entscheiden:
ASSERT ( 18446744073709551606ULL == - 10 );
Libassert bietet zwei Header <libassert/assert-catch2.hpp> und <libassert/assert-gtest.hpp> zur Verwendung mit Catch2 und Googletest.
Beispielausgabe von GTEST:

Weitere Informationen unten.
Libassert liefert drei Arten von Behauptungen, je nachdem, wann es überprüft werden sollte und wie es interpretiert werden sollte:
| Name | Wirkung |
|---|---|
DEBUG_ASSERT | Überprüft in Debug, kein CodeGen in der Veröffentlichung |
ASSERT | Sowohl im Debug- als auch im Release -Builds eingecheckt |
ASSUME | Überprüft in Debug, if(!(expr)) { __builtin_unreachable(); } in der Veröffentlichung |
Bedingungslose Behauptungen
| Name | Wirkung |
|---|---|
PANIC | Auslöser sowohl im Debug- als auch in der Veröffentlichung |
UNREACHABLE | Im Debug ausgelöst, als unerreichbar in der Freisetzung markiert. |
Ein Vorteil von PANIC und UNREACHABLE über ASSERT(false, ...) ist, dass der Compiler [[noreturn]] erhält.
ASSUME markiert den Fail -Pfad als unerreichbar in der Freigabe und liefert möglicherweise hilfreiche Informationen für den Optimierer. Dies ist nicht das Standardverhalten für alle Behauptungen, da die unmittelbare Konsequenz davon ist, dass das Aussagen von Behauptungen in -DNDEBUG zu UB führen kann und es besser ist, dies sehr explizit zu machen.
Assertion-Varianten FILE* file = ASSERT_VAL(fopen(path, "r"), "Failed to open file"); die in einem Ausdruck in der Leitung verwendet werden können, z. , sind auch erhältlich:
| Name | Wirkung |
|---|---|
DEBUG_ASSERT_VAL | In Debug überprüft, muss sowohl im Debug als auch in der Veröffentlichung bewertet werden |
ASSERT_VAl | Sowohl im Debug- als auch im Release -Builds eingecheckt |
ASSUME_VAL | Überprüft in Debug, if(!(expr)) { __builtin_unreachable(); } in der Veröffentlichung |
Hinweis: Selbst in der Veröffentlichung erstellt der Ausdruck für DEBUG_ASSERT_VAL im Gegensatz zu DEBUG_ASSERT noch. Wenn das Ergebnis nicht genutzt ist und keine Nebenwirkungen erzeugt, wird es natürlich optimiert.
Leistung: Was die Laufzeitleistung betrifft, so sind die Auswirkungen auf Callsites unter -Og oder höher sehr minimal. Der schnelle Weg im Code (dh, bei dem die Behauptung nicht fehlschlägt), ist schnell. Es ist eine Menge Arbeit erforderlich, um Behauptungsfehler zu verarbeiten, sobald sie stattfinden. Da jedoch Versagen selten sein sollten, sollte dies keine Rolle spielen.
Kompilierungsgeschwindigkeiten: Es gibt eine Kompilierungszeitkosten, die mit allen für die Magie dieser Bibliothek erforderlichen Vorlagen-Instanziationen verbunden sind.
Andere:
Notiz
Wegen der Expressionszersetzung, ASSERT(1 = 2); kompiliert.
Alle Behauptungsfunktionen sind Makros. Hier sind einige Pseudodeklarationen für die Verbindung mit ihnen:
void DEBUG_ASSERT (expression, [optional message], [optional extra diagnostics, ...]);
void ASSERT (expression, [optional message], [optional extra diagnostics, ...]);
void ASSUME (expression, [optional message], [optional extra diagnostics, ...]);
decltype ( auto ) DEBUG_ASSERT_VAL(expression, [optional message], [optional extra diagnostics, ...]);
decltype ( auto ) ASSERT_VAL (expression, [optional message], [optional extra diagnostics, ...]);
decltype ( auto ) ASSUME_VAL (expression, [optional message], [optional extra diagnostics, ...]);
void PANIC ([optional message], [optional extra diagnostics, ...]);
void UNREACHABLE ([optional message], [optional extra diagnostics, ...]); -DLIBASSERT_PREFIX_ASSERTIONS können verwendet werden, um diese Makros mit LIBASSERT_ zu präfixen. Dies ist nützlich, um die Behauptungen von Libassert zu wickeln.
-DLIBASSERT_LOWERCASE kann verwendet werden, um die Aliase debug_assert und assert für DEBUG_ASSERT und ASSERT aktivieren. Siehe: Ersetzen von <Cassert>.
expression Der expression wird automatisch zerlegt, sodass diagnostische Informationen bereitgestellt werden können. Der resultierende Typ muss in boolean konvertierbar sein.
Die Operation zwischen linker und rechter Handseiten der oberen Operation im Expressionsbaum wird durch ein Funktionsobjekt bewertet.
HINWEIS: Boolesche logische Operatoren ( && und || ) werden aufgrund von Kurzschaltungen standardmäßig nicht zersetzt.
assertion message Es kann eine optionale Assertion -Nachricht bereitgestellt werden. Wenn das erste Argument, das nach dem Ausdruck des Assertionsausdrucks oder des ersten Arguments in Panik/nicht erreichbar ist, ein String -Typ ist, wird er als Meldung verwendet (wenn Sie möchten, dass der erste Parameter, der zufällig eine Zeichenfolge ist, ein zusätzlicher diagnostischer Wert ist, der stattdessen einfach eine leere Zeichenfolge zuerst übergeben, dh ASSERT(foo, "", str); ).
Hinweis: Der Ausdruck der Assertion -Nachrichten wird nur im Fehlerpfad der Behauptung bewertet.
extra diagnosticsEs kann eine willkürliche Anzahl zusätzlicher diagnostischer Werte bereitgestellt werden. Diese werden unter der Expressionsdiagnose angezeigt, wenn ein Scheck fehlschlägt.
HINWEIS: Zusätzliche Diagnostik werden nur im Fehlerpfad der Behauptung bewertet.
Es gibt eine spezielle Handhabung, wenn errno bereitgestellt wird: Der Wert von strerror wird automatisch angezeigt.
Um die einfache Integration in Code _VAL -Varianten zu erleichtern, werden ein Wert aus dem Assert -Ausdruck zurückgegeben. Der zurückgegebene Wert wird wie folgt bestimmt:
ASSERT_VAL(foo()); oder ASSERT_VAL(false); ) im Ausdruck des Assertionsausdrucks wird der Wert des Ausdrucks einfach zurückgegeben.== ,! != , < , <= , > , >= , && , || oder oder eine Zuordnung oder eine Verbindungszuordnung, dann wird der Wert des linken Operanden zurückgegeben.& , | ^ << >> IE, ASSERT_VAL(foo() > 2); Gibt das berechnete Ergebnis von foo() und ASSERT_VAL(x & y); Gibt das berechnete Ergebnis von x & y zurück;
Wenn der Wert aus dem ausgewählten Ausdruck des Aussagens, der zurückgegeben wird, ein LVALUE ist, ist der Typ des Behauptungsaufrufs eine LVALUE -Referenz. Wenn der Wert aus dem Ausdruck des Assertion ein RValue ist, ist der Typ des Anrufs ein RValue.
namespace libassert {
[[nodiscard]] std::string stacktrace (
int width = 0 ,
const color_scheme& scheme = get_color_scheme(),
std::size_t skip = 0
);
template < typename T> [[nodiscard]] std::string_view type_name () noexcept ;
template < typename T> [[nodiscard]] std::string pretty_type_name () noexcept ;
template < typename T> [[nodiscard]] std::string stringify ( const T& value);
}stacktrace : Erzeugt eine Stapelspur, Formate bis zur angegebenen Breite (0 für keine Breite Formatierung)type_name : Gibt den Typ -Namen von t zurückpretty_type_name : Gibt den bekannten Typnamen für t zurückstringify : Erzeugt eine Debug -Stringung eines Wertes namespace libassert {
void enable_virtual_terminal_processing_if_needed ();
inline constexpr int stdin_fileno = 0 ;
inline constexpr int stdout_fileno = 1 ;
inline constexpr int stderr_fileno = 2 ;
bool isatty ( int fd);
[[nodiscard]] int terminal_width ( int fd);
}enable_virtual_terminal_processing_if_needed : Aktivieren Sie die ANSI -Escape -Sequenzen für Terminals unter Windows, die für die Farbausgabe benötigt werden.isatty : Gibt true zurück, wenn der Dateideskriptor einem Terminal entsprichtterminal_width : Gibt die Breite des Terminals zurück, die durch FD oder 0 auf dem Fehler dargestellt wird namespace libassert {
// NOTE: string view underlying data should have static storage duration, or otherwise live as
// long as the scheme is in use
struct color_scheme {
std::string_view string, escape, keyword, named_literal, number, punctuation, operator_token,
call_identifier, scope_resolution_identifier, identifier, accent, unknown, reset;
static const color_scheme ansi_basic;
static const color_scheme ansi_rgb;
static const color_scheme blank;
};
void set_color_scheme ( const color_scheme&);
const color_scheme& get_color_scheme ();
} Standardmäßig wird color_scheme::ansi_rgb verwendet. Um Farben zu deaktivieren, verwenden Sie color_scheme::blank .
set_color_scheme : Legt das Farbschema für den Standard -Assertion -Handler fest, wenn STDERR ein Terminal ist namespace libassert {
void set_separator (std::string_view separator);
}set_separator : Legt den Separator zwischen Expression und Wert in der Assertion -Diagnoseausgabe fest. Standard: => . HINWEIS: Nicht thread-sicher. namespace libassert {
enum class literal_format_mode {
infer, // infer literal formats based on the assertion condition
no_variations, // don't do any literal format variations, just default
fixed_variations // always use a fixed set of formats (in addition to the default format)
};
void set_literal_format_mode (literal_format_mode);
enum class literal_format : unsigned {
// integers and floats are decimal by default, chars are of course chars, and everything
// else only has one format that makes sense
default_format = 0 ,
integer_hex = 1 ,
integer_octal = 2 ,
integer_binary = 4 ,
integer_character = 8 , // format integers as characters and characters as integers
float_hex = 16 ,
};
[[nodiscard]] constexpr literal_format operator |(literal_format a, literal_format b);
void set_fixed_literal_format (literal_format);
}set_literal_format_mode : Legt fest, ob die Bibliothek wörtliche Variationen anzeigen oder sie schließen sollset_fixed_literal_format : Setzen Sie eine feste Konfiguration des Literalformates und ändert automatisch die literal_format_mode; Beachten Sie, dass das Standardformat immer zusammen mit anderen verwendet wird namespace libassert {
enum class path_mode {
full, // full path is used
disambiguated, // only enough folders needed to disambiguate are provided
basename, // only the file name is used
};
LIBASSERT_EXPORT void set_path_mode (path_mode mode);
}set_path_mode : Legt den Pfadverkürzungsmodus für die Ausgabe der Behauptung fest. Standard: path_mode::disambiguated . namespace libassert {
enum class assert_type {
debug_assertion,
assertion,
assumption,
panic,
unreachable
};
struct LIBASSERT_EXPORT binary_diagnostics_descriptor {
std::string left_expression;
std::string right_expression;
std::string left_stringification;
std::string right_stringification;
};
struct extra_diagnostic {
std::string_view expression;
std::string stringification;
};
struct LIBASSERT_EXPORT assertion_info {
std::string_view macro_name;
assert_type type;
std::string_view expression_string;
std::string_view file_name;
std:: uint32_t line;
std::string_view function;
std::optional<std::string> message;
std::optional<binary_diagnostics_descriptor> binary_diagnostics;
std::vector<extra_diagnostic> extra_diagnostics;
size_t n_args;
std::string_view action () const ;
const cpptrace::raw_trace& get_raw_trace () const ;
const cpptrace::stacktrace& get_stacktrace () const ;
[[nodiscard]] std::string header ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string tagline ( const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string location () const ;
[[nodiscard]] std::string statement ( const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string print_binary_diagnostics ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string print_extra_diagnostics ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string print_stacktrace ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
[[nodiscard]] std::string to_string ( int width = 0 , const color_scheme& scheme = get_color_scheme()) const ;
};
} Debug Assertion failed at demo.cpp:194: void foo::baz(): Internal error with foobars
debug_assert(open(path, 0) >= 0, ...);
Where:
open(path, 0) => -1
Extra diagnostics:
errno => 2 "No such file or directory"
path => "/home/foobar/baz"
Stack trace:
#1 demo.cpp:194 foo::baz()
#2 demo.cpp:172 void foo::bar<int>(std::pair<int, int>)
#3 demo.cpp:396 main
Debug Assertion failed : assertion_info.action()demo.cpp:194 : assertion_info.file_name UND assertion_info.linevoid foo::baz() : assertion_info.pretty_functionInternal error with foobars : assertion_info.messagedebug_assert : assertion_info.macro_nameopen(path, 0) >= 0 : assertion_info.expression_string... : bestimmt durch assertion_info.n_args die die Gesamtzahl der Argumente enthält, die an das Assertion -Makro übergeben wurdenopen(path, 0) : assertion_info.binary_diagnostics.left_expression-1 : assertion_info.binary_diagnostics.left_stringification0 => 0 nicht nützlich ist)errno : assertion_info.extra_diagnostics[0].expression2 "No such file or directory" : assertion_info.extra_diagnostics[0].stringificationassertion_info.get_stacktrace() oder assertion_info.get_raw_trace() um die Spur zu erhalten, ohne sie zu behebenHelfer:
assertion_info.header() :
Debug Assertion failed at demo.cpp:194: void foo::baz(): Internal error with foobars
debug_assert(open(path, 0) >= 0, ...);
Where:
open(path, 0) => -1
Extra diagnostics:
errno => 2 "No such file or directory"
path => "/home/foobar/baz"
assertion_info.tagline() :
Debug Assertion failed at demo.cpp:194: void foo::baz(): Internal error with foobars
assertion_info.location() :
Notiz
Die Pfadverarbeitung wird gemäß dem Pfadmodus durchgeführt
demo.cpp:194
assertion_info.statement() :
debug_assert(open(path, 0) >= 0, ...);
assertion_info.print_binary_diagnostics() :
Where:
open(path, 0) => -1
assertion_info.print_extra_diagnostics() :
Extra diagnostics:
errno => 2 "No such file or directory"
path => "/home/foobar/baz"
assertion_info.print_stacktrace() :
Stack trace:
#1 demo.cpp:194 foo::baz()
#2 demo.cpp:172 void foo::bar<int>(std::pair<int, int>)
#3 demo.cpp:396 main
Libassert bietet einen Anpassungspunkt für benutzerdefinierte Typen:
template <> struct libassert ::stringifier<MyObject> {
std::string stringify ( const MyObject& type) {
return ...;
}
};Standardmäßig werden alle benutzerdefinierten Container-ähnlichen Typen automatisch festgelegt.
Zusätzlich kann LIBASSERT_USE_FMT verwendet werden, damit Libassert fmt::formatter s verwenden kann.
Zuletzt können alle Typen mit einem Ostream operator<< Überladung angestrebt werden.
namespace libassert {
void set_failure_handler ( void (*handler)( const assertion_info&));
}set_failure_handler : Legt den Assertion -Handler für das Programm fest.Ein Beispiel für Behauptung, die dem Standard -Handler ähnelt:
void libassert_default_failure_handler ( const assertion_info& info) {
libassert::enable_virtual_terminal_processing_if_needed (); // for terminal colors on windows
std::string message = info. to_string (
libassert::terminal_width (libassert::stderr_fileno),
libassert::isatty (libassert::stderr_fileno)
? libassert::get_color_scheme ()
: libassert::color_scheme::blank
);
std::cerr << message << std::endl;
switch (info. type ) {
case libassert::assert_type::assertion:
case libassert::assert_type::debug_assertion:
case libassert::assert_type::assumption:
case libassert::assert_type::panic:
case libassert::assert_type::unreachable:
( void ) fflush (stderr);
std::abort ();
// Breaking here as debug CRT allows aborts to be ignored, if someone wants to make a
// debug build of this library
break ;
default :
std::cerr << " Critical error: Unknown libassert::assert_type " << std::endl;
std::abort ( 1 );
}
}Standardmäßig Abbruch von allen Behauptungen. Es kann jedoch wünschenswert sein, eine Ausnahme von einigen oder allen Behauptungen zu machen, anstatt abzubrechen.
Wichtig
Fehlerhandler dürfen nicht für assert_type::panic und assert_type::unreachable zurückkehren.
Libassert unterstützt programmatische Haltepunkte bei Behauptungen, die Behauptungen nicht mehr debugger-freundlich zu gestalten, indem sie die Assertion-Linie im Gegensatz zu mehreren Schichten tief in einem Callstack durchbricht:

Diese Funktionalität wird derzeit abgelehnt und kann durch Definieren von LIBASSERT_BREAK_ON_FAIL aktiviert werden. Dies erfolgt am besten als Compiler -Flag: -DLIBASSERT_BREAK_ON_FAIL oder /DLIBASSERT_BREAK_ON_FAIL .
Innen prüft die Bibliothek nach dem Präsidium eines Debuggers, bevor er einen Anweisungen zum Breakpoint des Debuggers ausführte. Standardmäßig wird der Scheck nur einmal beim ersten Ausfall der Behauptung durchgeführt. In einigen Szenarien kann es wünschenswert sein, diese Überprüfung zu konfigurieren, die immer durchgeführt werden soll, z. B. wenn Sie einen benutzerdefinierten Behauptungshandler verwenden, der eine Ausnahme anstatt abgebrochen zu haben, und Sie sich möglicherweise von einem Behauptungsfehler erholen können, der später zusätzliche Fehler ermöglicht. Sie können libassert::set_debugger_check_mode verwenden, um zu steuern, wie diese Überprüfung durchgeführt wird:
namespace libassert {
enum class debugger_check_mode {
check_once,
check_every_time,
};
void set_debugger_check_mode (debugger_check_mode mode) noexcept ;
}Die Bibliothek enthüllt auch ihre internen Versorgungsunternehmen für das Festlegen von Haltepunkten und die Überprüfung, ob das Programm debugged wird:
namespace libassert {
bool is_debugger_present () noexcept ;
}
# define LIBASSERT_BREAKPOINT () <...internals...>
# define LIBASSERT_BREAKPOINT_IF_DEBUGGING () <...internals...>Diese API ahmt die API von P2514 nach, die auf C ++ 26 angenommen wurde.
Ein Hinweis zu constexpr : Für Clang und MSVC -Libassert kann jedoch Compiler -Intrinsics für die GCC -Inline -Montage erforderlich sind. Die Inline-Assembly ist in den Funktionen von ContexPr-Funktionen vor-C ++ 20 nicht erlaubt. GCC unterstützt sie jedoch mit einer Warnung nach GCC 10, und die Bibliothek kann die Warnung für GCC 12 überraschen.
Definiert:
LIBASSERT_USE_MAGIC_ENUM : Verwenden Sie Magic Enum zum String -Enum -WertenLIBASSERT_DECOMPOSE_BINARY_LOGICAL : zersetzen && und ||LIBASSERT_SAFE_COMPARISONS : Safe Safe Signed-Signed-Vergleiche für zersetzte Ausdrücke aktivierenLIBASSERT_PREFIX_ASSERTIONS : Präfixe alle Assertion -Makros mit LIBASSERT_LIBASSERT_USE_FMT : Ermöglicht die Integration von libfmtLIBASSERT_NO_STRINGIFY_SMART_POINTER_OBJECTS : DeaktivierenCmake:
LIBASSERT_USE_EXTERNAL_CPPTRACE : Verwenden Sie eine externe CPPTrace, anstatt die Bibliothek mit FetchContent zu erwerbenLIBASSERT_USE_EXTERNAL_MAGIC_ENUM : Verwenden Sie eine externe Magie, anstatt die Bibliothek mit FetchContent zu erwerbenNotiz
Aufgrund des nicht konformanten Präprozessors von MSVC gibt es keine einfache Möglichkeit, Behauptungsverpackungen bereitzustellen. Um Testbibliotheksintegrationen /Zc:preprocessor ist erforderlich.
Libassert bietet eine Catch2-Integration in libassert/assert-catch2.hpp :
# include < libassert/assert-catch2.hpp >
TEST_CASE ( " 1 + 1 is 2 " ) {
ASSERT ( 1 + 1 == 3 );
}
Derzeit ist das einzige bereitgestellte Makro ASSERT , das eine interne REQUIRE durchführt.
HINWEIS: Bevor V3.6.0 ANSI -Farbcodes die Zeilenverpackung von Catch2 stören, sodass die Farbe bei älteren Versionen deaktiviert ist.
Libassert bietet eine GTEST-Integration in libassert/assert-gtest.hpp :
# include < libassert/assert-gtest.hpp >
TEST (Addition, Arithmetic) {
ASSERT ( 1 + 1 == 3 );
}
Derzeit liefert Libassert ASSERT und EXPECT Makros für GTEST.
Das ist nicht so hübsch, wie ich möchte, aber es erledigt den Job.
Diese Bibliothek zielt auf> = C ++ 17 und unterstützt alle wichtigen Compiler und alle wichtigen Plattformen (Linux, MacOS, Windows und Mingw).
Hinweis: Die Bibliothek beruht auf einigen Compiler -Erweiterungen und Compiler -spezifischen Funktionen, sodass sie nicht mit -pedantic kompatibel ist.
Mit CMake FetchContent:
include (FetchContent)
FetchContent_Declare(
libassert
GIT_REPOSITORY https://github.com/jeremy-rifkin/libassert.git
GIT_TAG v2.1.2 # <HASH or TAG>
)
FetchContent_MakeAvailable(libassert)
target_link_libraries (your_target libassert::assert)Hinweis: Unter Windows und MacOS werden zusätzliche Arbeiten empfohlen, siehe Plattformlogistik unten.
Stellen Sie sicher, dass Sie mit -DCMAKE_BUILD_TYPE=Debug oder -DDCMAKE_BUILD_TYPE=RelWithDebInfo für Symbole und Zeileninformationen konfigurieren.
git clone https://github.com/jeremy-rifkin/libassert.git
git checkout v2.1.2
mkdir libassert/build
cd libassert/build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j
sudo make installVerwendung durch CMake:
find_package (libassert REQUIRED)
target_link_libraries (<your target > libassert::assert) Stellen Sie sicher, dass Sie mit -DCMAKE_BUILD_TYPE=Debug oder -DDCMAKE_BUILD_TYPE=RelWithDebInfo für Symbole und Zeileninformationen konfigurieren.
Oder mit -lassert kompilieren:
g++ main.cpp -o main -g -Wall -lassert
./mainWenn Sie einen Fehler in den Zeilen von erhalten
error while loading shared libraries: libassert.so: cannot open shared object file: No such file or directory
Möglicherweise müssen Sie sudo /sbin/ldconfig ausführen, um alle erforderlichen Links zu erstellen und Caches zu aktualisieren, damit das System libcpptrace finden kann (ich musste dies auf Ubuntu tun). Nur wenn systemweit installiert wird. Normalerweise tut Ihr Paket -Manager bei der Installation neuer Bibliotheken für Sie.
git clone https: // github.com / jeremy - rifkin / libassert.git
git checkout v2. 1.2
mkdir libassert / build
cd libassert / build
cmake . . - DCMAKE_BUILD_TYPE = Release
msbuild libassert.sln
msbuild INSTALL.vcxprojHinweis: Sie müssen als Administrator in einem Entwickler PowerShell ausgeführt oder vcvarsall.bat mit Visual Studio verteilt, um die richtigen Umgebungsvariablen zu erhalten.
So installieren Sie nur für den lokalen Benutzer (oder ein benutzerdefiniertes Präfix):
git clone https://github.com/jeremy-rifkin/libassert.git
git checkout v2.1.2
mkdir libassert/build
cd libassert/build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX= $HOME /wherever
make -j
sudo make installVerwendung durch CMake:
find_package (libassert REQUIRED PATHS $ENV{HOME} /wherever)
target_link_libraries (<your target > libassert::assert)Manuell verwenden:
g++ main.cpp -o main -g -Wall -I$HOME/wherever/include -L$HOME/wherever/lib -lassert
Um die Bibliothek ohne CMAKE zu verwenden, folgen Sie zunächst die Installationsanweisungen bei systemweiter Installation, lokaler Benutzerinstallation oder Paketmanagern.
Verwenden Sie die folgenden Argumente, um mit Libassert zu kompilieren:
| Compiler | Plattform | Abhängigkeiten |
|---|---|---|
| GCC, Clang, Intel usw. | Linux/macOS/UNIX | -libassert -I[path] [cpptrace args] |
| Mingw | Fenster | -libassert -I[path] [cpptrace args] |
| MSVC | Fenster | assert.lib /I[path] [cpptrace args] |
| Klang | Fenster | -libassert -I[path] [cpptrace args] |
Geben Sie für den [path] Platzhalter in -I[path] und /I[path] den Pfad zum integrierten Ordner mit libassert/assert.hpp .
Wenn Sie statisch verlinken, müssen Sie zusätzlich -DLIBASSERT_STATIC_DEFINE angeben.
Für den [cpptrace args] beziehen sich der Platzhalter auf die CPPTrace -Dokumentation.
Libassert ist über Conan unter https://conan.io/center/recipes/libassert erhältlich.
[requires]
libassert/2.1.2
[generators]
CMakeDeps
CMakeToolchain
[layout]
cmake_layout
# ...
find_package (libassert REQUIRED)
# ...
target_link_libraries (YOUR_TARGET libassert::assert) vcpkg install libassert
find_package (libassert CONFIG REQUIRED)
target_link_libraries (YOUR_TARGET PRIVATE libassert::assert)Windows und MacOS benötigen ein wenig zusätzliche Arbeit, um alles an den richtigen Ort zu bringen
Kopieren der Bibliothek .dll unter Windows:
# Copy the assert.dll on windows to the same directory as the executable for your_target.
# Not required if static linking.
if ( WIN32 )
add_custom_command (
TARGET your_target POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:libassert::assert>
$<TARGET_FILE_DIR:your_target>
)
endif ()Auf macOS wird empfohlen, eine DSYM -Datei zu generieren, die Debug -Informationen für Ihr Programm enthält:
In Xcode cmake kann dies mit erfolgen
set_target_properties (your_target PROPERTIES XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym" ) Und außerhalb von Xcode kann dies mit dsymutil yourbinary erfolgen:
# Create a .dSYM file on macos. Currently required, but hopefully not for long
if ( APPLE )
add_custom_command (
TARGET your_target
POST_BUILD
COMMAND dsymutil $<TARGET_FILE:your_target>
)
endif () Diese Bibliothek ist kein Drop-In-Ersatz für <cassert> . -DLIBASSERT_LOWERCASE kann verwendet werden, um Aliase für die Assertion -Makros in Kleinbuchstaben zu erstellen. Beachten Sie jedoch, dass ASSERT von Libassert noch in der Freigabe überprüft wird. Um <cassert> Verwendung durch Libassert zu ersetzen, ersetzen Sie assert durch DEBUG_ASSERT oder erstellen Sie einen Alias in den folgenden Zeilen:
# define assert (...) DEBUG_ASSERT(__VA_ARGS__) Eine Sache, die sich bewusst ist: Übergeordnetes assert von Cassert ist technisch nicht vom Standard zulässig, aber dies sollte für einen vernünftigen Compiler kein Problem sein.
Nein, noch nicht.
cpp-sort Selbst bei Konstrukten wie assert_eq fehlt häufig die Behauptungsdiagnostik. Zum Beispiel werden in Rost die linken und rechten Werte angezeigt, aber nicht die Ausdrücke selbst:
fn main ( ) {
let count = 4 ;
assert_eq ! ( count , 2 ) ;
} thread 'main' panicked at 'assertion failed: `(left == right)`
left: `4`,
right: `2`', /app/example.rs:3:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Dies ist nicht so hilfreich, wie es sein könnte.
Funktionalität Andere Sprachen / ihre Standardbibliotheken bieten:
| C/C ++ | Rost | C# | Java | Python | JavaScript | Libassert | |
|---|---|---|---|---|---|---|---|
| Ausdruckszeichenfolge | ✔️ | ✔️ | |||||
| Standort | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Stapelspur | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | |
| Behauptungsnachricht | ** | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Zusätzliche Diagnostik | * | * | * | * | ✔️ | ||
| Binäre Spezialisierungen | ✔️ | ✔️ | ✔️ | ||||
| Automatische Ausdruckszerlegung | ✔️ | ||||||
| Subexpressionszeichenfolgen | ✔️ |
* : Möglich durch String-Formatierung, aber das ist sub-ideal.
** : assert(expression && "message") wird üblicherweise verwendet, dies ist jedoch sub-ideal und ermöglicht nur literalische Zeichenfolgen.
Extras:
| C/C ++ | Rost | C# | Java | Python | JavaScript | Libassert | |
|---|---|---|---|---|---|---|---|
| Syntax -Hervorhebung | ? | ✔️ | |||||
| Wörtliche Formatierungskonsistenz | ✔️ | ||||||
| Ausdruckszeichenfolgen und Ausdruckswerte überall | ✔️ | ||||||
| Rückgabewerte aus dem Asser | ✔️ |