Vermeiden von Warnungen über nicht verwendete Variablen bei der Verwendung von assert() in einem Release-Build

Lesezeit: 8 Minuten

Vermeiden von Warnungen uber nicht verwendete Variablen bei der Verwendung
Hexagon

Manchmal wird eine lokale Variable nur zu dem Zweck verwendet, sie in einem assert() zu überprüfen, etwa so –

int Result = Func();
assert( Result == 1 );

Beim Kompilieren von Code in einem Release-Build sind assert()s normalerweise deaktiviert, sodass dieser Code möglicherweise eine Warnung ausgibt, dass Result festgelegt, aber nie gelesen wird.

Eine mögliche Problemumgehung ist –

int Result = Func();
if ( Result == 1 )
{
    assert( 0 );
}

Aber es erfordert zu viel Tipparbeit, ist nicht schön für die Augen und führt dazu, dass die Bedingung immer überprüft wird (ja, der Compiler optimiert die Überprüfung möglicherweise weg, aber trotzdem).

Ich suche nach einer alternativen Möglichkeit, dieses assert() so auszudrücken, dass die Warnung nicht ausgelöst wird, aber dennoch einfach zu verwenden ist und die Semantik von assert() nicht geändert wird.

(Die Warnung mit einem #pragma in diesem Codebereich zu deaktivieren ist keine Option, und das Verringern der Warnstufen, damit sie verschwindet, ist auch keine Option …).

  • Obermenge: stackoverflow.com/questions/3599160/…

    – Ciro Santilli

    15. Februar ’19 um 10:17

Vermeiden von Warnungen uber nicht verwendete Variablen bei der Verwendung
Graeme Perrow

Wir verwenden ein Makro, um gezielt anzuzeigen, wenn etwas nicht verwendet wird:

#define _unused(x) ((void)(x))

Dann hätten Sie in Ihrem Beispiel:

int Result = Func();
assert( Result == 1 );
_unused( Result ); // make production build happy

Auf diese Weise (a) ist der Produktionsbuild erfolgreich und (b) ist im Code offensichtlich, dass die Variable nicht verwendet wird von Entwurf, nicht dass es nur vergessen wurde. Dies ist besonders hilfreich, wenn Parameter einer Funktion nicht verwendet werden.

  • Bis Ergebnis wird später verwendet, und dann ist es nur verwirrend 🙂 Aber netter Vorschlag +1.

    – Brian R. Bondy

    22. Apr. 09 um 14:03

  • Außerdem wird Func immer noch aufgerufen (es sei denn, der Optimierer weiß, dass es keine Nebenwirkungen hat)

    – xtofl

    22. Apr. ’09 um 15:31

  • Das ist eine gute Idee. Ich verwende es für Parameter von Funktionen, die nicht verwendet werden, aber die Verwendung für assert()s ist sicherlich auch eine nette Option. Vielleicht kann stattdessen ein Makro namens FOR_ASSERT() verwendet werden, um die Argumentation zu verdeutlichen. Danke!

    – Sechseck

    22. Apr. 09 um 16:04

  • @xtofl: Das ist ein Punkt, aber mit ziemlicher Sicherheit du wollen Func() aufgerufen werden – sonst hätten Sie einfach “assert(Func() == 1);” schreiben können. an erster Stelle.

    – j_random_hacker

    22. Apr. 09 um 16:12

  • Sie können auch Ihre assert ein Makro wie: #define assert(X,Y) __assert(X,Y); _unused(X) wobei X Ihre Variable und Y die Bedingung ist. Verwendung in Ihrem Fall: assert(Result, 1);

    – Gui13

    21. Okt ’11 um 8:51


Ich könnte keine bessere Antwort geben als diese, die dieses Problem und viele mehr anspricht:

Dumme C++-Tricks: Abenteuer in Assertion

#ifdef NDEBUG
#define ASSERT(x) do { (void)sizeof(x);} while (0)
#else
#include <assert.h>
#define ASSERT(x) assert(x)
#endif

  • Für die Faulen, in Release-Builds: #define ASSERT(X) do { (void)sizeof(x); } während(0)

    – vielbeinig

    30. Mai ’13 um 4:05


  • Das gefällt mir besser, weil es sogar in dem Fall funktioniert, wo x ist nicht eine Variable. Sie müssen also kein anderes Makro verwenden, je nachdem, was Sie behaupten… Auch der Link ist definitiv lesenswert.

    – fjardon

    9. Juni ’19 um 9:29

1641756403 680 Vermeiden von Warnungen uber nicht verwendete Variablen bei der Verwendung
Gathar

Ab C++17 kann die Variable mit einem Attribut versehen werden.

[[maybe_unused]] int Result = Func();
assert( Result == 1 );

Sehen https://en.cppreference.com/w/cpp/language/attributes/maybe_unused für Details.

Das ist besser als die (void)Result Trick, weil Sie die Variablendeklaration direkt dekorieren, anstatt nachträglich etwas hinzuzufügen.

  • Es ist erwähnenswert, dass “recent C++” == seit C++17

    – noamgot

    11. August ’20 bei 7:51


Sie könnten ein weiteres Makro erstellen, mit dem Sie die Verwendung einer temporären Variablen vermeiden können:

#ifndef NDEBUG
#define Verify(x) assert(x)
#else
#define Verify(x) ((void)(x))
#endif

// asserts that Func()==1 in debug mode, or calls Func() and ignores return
// value in release mode (any braindead compiler can optimize away the comparison
// whose result isn't used, and the cast to void suppresses the warning)
Verify(Func() == 1);

Vermeiden von Warnungen uber nicht verwendete Variablen bei der Verwendung
Daniel Daranas

int Result = Func();
assert( Result == 1 );

Diese Situation bedeutet, dass Sie im Freigabemodus wirklich Folgendes möchten:

Func();

Aber Func ist nicht leer, dh es gibt ein Ergebnis zurück, dh es ist a Anfrage.

Vermutlich neben der Rückgabe eines Ergebnisses, Func modifiziert etwas (warum sonst die Mühe machen, es aufzurufen und sein Ergebnis nicht zu verwenden?), dh es ist a Befehl.

Bis zum Prinzip der Befehls-Abfrage-Trennung (1), Func sollte nicht gleichzeitig ein Befehl und eine Abfrage sein. Mit anderen Worten, Abfragen sollten keine Nebeneffekte haben und das “Ergebnis” von Befehlen sollte durch die verfügbaren Abfragen zum Zustand des Objekts dargestellt werden.

Cloth c;
c.Wash(); // Wash is void
assert(c.IsClean());

Ist besser als

Cloth c;
bool is_clean = c.Wash(); // Wash returns a bool
assert(is_clean);

Ersteres gibt dir keine Warnung deiner Art, letzteres schon.

Also, kurz gesagt, meine Antwort ist: Schreiben Sie keinen Code wie diesen 🙂

Aktualisierung (1): Sie haben nach Referenzen zu den . gefragt Prinzip der Befehls-Abfrage-Trennung. Wikipedia ist eher informativ. Ich habe über diese Designtechnik gelesen in Objektorientierte Softwarekonstruktion, 2. Auflage von Bertrand Meyer.

Aktualisierung (2): j_random_hacker kommentiert “OTOH, jede “Befehls”-Funktion f(), die zuvor einen Wert zurückgegeben hat, muss jetzt eine Variable last_call_to_f_succeeded oder ähnliches setzen. Dies gilt nur für Funktionen, die in ihrem Vertrag nichts versprechen, dh Funktionen, die “erfolgreich” sein könnten oder nicht, oder ein ähnliches Konzept. Mit Design by Contract, wird eine relevante Anzahl von Funktionen haben Nachbedingungen, so dass nach “Empty()” das Objekt “IsEmpty()” ist und nach “Encode()” die Nachrichtenzeichenfolge “IsEncoded()” ist, ohne dass eine Überprüfung erforderlich ist. Auf die gleiche Weise und etwas symmetrisch rufen Sie nicht vor jedem Aufruf einer Prozedur “X()” eine spezielle Funktion “IsXFeasible()” auf; weil Sie normalerweise wissen, dass Sie zum Zeitpunkt Ihres Anrufs die Voraussetzungen von X erfüllen.

  • Dieser Rat ist zu allgemein. Wie wäre es mit list.Remove? Hier kannst du müssen um den Rückgabewert zu haben, ob ein Element entfernt wurde. list.WasSuccessfullyRemoved() wäre falsch.

    – Konrad Rudolph

    22. Apr. 09 um 14:34

  • Einen Fehlercode von einer Funktion zurückzugeben ist völlig in Ordnung, aber Sie scheinen die Praxis zu verdammen.

    – John Dibling

    22. Apr. 09 um 15:47 Uhr

  • @Daniel: Könnten Sie die Gründe für das “Prinzip der Trennung von Befehlen und Abfragen” erklären? Ein Link wäre gut. Danke!

    – j_random_hacker

    22. Apr. 09 um 16:13

  • @Daniel: Danke für das Update. Darin sehe ich die Vorteile. OTOH, jede “Befehls”-Funktion f(), die zuvor einen Wert zurückgegeben hat, muss jetzt eine Variable last_call_to_f_succeeded oder ähnliches setzen, was möglicherweise Probleme für wiedereintretenden/multithreaded Code verursacht (wie im Artikel erwähnt). Aber ja, CQS scheint definitiv ein gültiger, die Logik vereinfachender Ansatz zu sein, der es wert ist, wenn möglich angewendet zu werden.

    – j_random_hacker

    23. Apr. ’09 um 9:03

  • @j_random_hacker: Wie bei allen Techniken unterliegt es immer einer Bewertung. In vielen Fällen gestalte ich so, gebe aber zu, dass ich manchmal die andere Strategie verwende, insbesondere in Fällen, in denen nichts über das Ergebnis ausgesagt werden kann, zB “FindFile()” oder “UpdateConfigurationFile()”. Es ist nur eine weitere Technik in Ihrem Toolset, die Sie mit Bedacht einsetzen sollten. Bleiben Sie jedoch gespannt auf das Update (2) 🙂

    – Daniel Daranas

    23. Apr. 09 um 9:17

Du könntest benutzen:

Check( Func() == 1 );

Und implementieren Sie Ihre Check(bool)-Funktion nach Belieben. Es kann entweder Assert verwenden oder eine bestimmte Ausnahme auslösen, in eine Protokolldatei oder in die Konsole schreiben, verschiedene Implementierungen in Debug und Release oder eine Kombination aus allen haben.

  • Dieser Rat ist zu allgemein. Wie wäre es mit list.Remove? Hier kannst du müssen um den Rückgabewert zu haben, ob ein Element entfernt wurde. list.WasSuccessfullyRemoved() wäre falsch.

    – Konrad Rudolph

    22. Apr. 09 um 14:34

  • Einen Fehlercode von einer Funktion zurückzugeben ist völlig in Ordnung, aber Sie scheinen die Praxis zu verdammen.

    – John Dibling

    22. Apr. 09 um 15:47 Uhr

  • @Daniel: Könnten Sie die Gründe für das “Prinzip der Trennung von Befehlen und Abfragen” erklären? Ein Link wäre gut. Danke!

    – j_random_hacker

    22. Apr. 09 um 16:13

  • @Daniel: Danke für das Update. Darin sehe ich die Vorteile. OTOH, jede “Befehls”-Funktion f(), die zuvor einen Wert zurückgegeben hat, muss jetzt eine Variable last_call_to_f_succeeded oder ähnliches setzen, was möglicherweise Probleme für wiedereintretenden/multithreaded Code verursacht (wie im Artikel erwähnt). Aber ja, CQS scheint definitiv ein gültiger, die Logik vereinfachender Ansatz zu sein, der es wert ist, wenn möglich angewendet zu werden.

    – j_random_hacker

    23. Apr. ’09 um 9:03

  • @j_random_hacker: Wie bei allen Techniken unterliegt es immer einer Bewertung. In vielen Fällen gestalte ich so, gebe aber zu, dass ich manchmal die andere Strategie verwende, insbesondere in Fällen, in denen nichts über das Ergebnis ausgesagt werden kann, zB “FindFile()” oder “UpdateConfigurationFile()”. Es ist nur eine weitere Technik in Ihrem Toolset, die Sie mit Bedacht einsetzen sollten. Bleiben Sie jedoch gespannt auf das Update (2) 🙂

    – Daniel Daranas

    23. Apr. 09 um 9:17

1641756403 946 Vermeiden von Warnungen uber nicht verwendete Variablen bei der Verwendung
Aelian

Mit C++17 können wir:

[[maybe_unused]] int Result = Func();

obwohl es im Vergleich zu einer Assert-Ersetzung etwas mehr Tipparbeit erfordert. Siehe diese Antwort.

Hinweis: Dies wurde hinzugefügt, da dies der erste Google-Treffer für “c++ Assertiere nicht verwendete Variable” ist.

.

236510cookie-checkVermeiden von Warnungen über nicht verwendete Variablen bei der Verwendung von assert() in einem Release-Build

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy