2012-04-08 13 views
1

Mein C-Code enthält viele Funktionen mit Zeigern zu anderen Strukturen als Parameter, die keine Nullzeiger sein sollten. Um meinen Code besser lesbar, ich beschlossen, diesen Code zu ersetzen:Verwenden von Makro, um Nullwerte zu überprüfen

if(arg1==NULL || arg2==NULL || arg3==NULL...) { 
    return SOME_ERROR; 
} 

Mit diesem Makro:

NULL_CHECK(arg1,arg2,...) 

Wie soll ich es schreiben, wenn die Anzahl der args unbekannt ist und sie verweisen auf verschiedene Strukturen? (Ich arbeite in C99)

Antwort

7

IMO die am meisten wartbare Lösung ist es, mehrere separate Anrufe zu schreiben, anstatt zu versuchen, "schlau" darüber zu bekommen.

Beispiel: Win32-Programmierer verwenden ein VERIFY-Makro, das eine Assertion zum Debug-Zeitpunkt ausführt (das Makro stellt sicher, dass die Assertions aus dem Freigabecode entfernt werden); Es ist nicht ungewöhnlich Funktionen, um zu sehen, die wie folgt beginnen:

int foo(void* arg1, char* str, int n) 
{ 
    VERIFY(arg1 != NULL); 
    VERIFY(str != NULL); 
    VERIFY(n > 0); 

Offensichtlich könnte man sehr leicht diese drei Zeilen in einer einzigen Zeile kondensieren, aber das Makro funktioniert am besten, wenn Sie dies nicht tun. Wenn Sie sie auf separate Zeilen setzen, wird eine fehlgeschlagene Behauptung Ihnen sagen, welche der drei Bedingungen nicht erfüllt sind, während Sie alle in derselben Anweisung nur Ihnen sagen, dass etwas fehlgeschlagen ist und Sie den Rest herausfinden können.

+4

+1; Es ist im Allgemeinen keine gute Idee, C-Makros zu schreiben, die die Syntax der Sprache ändern (hier durch Einfügen einer return-Anweisung in die Makrodefinition). Solche Aussagen zu verwenden, ist ein viel besserer Ansatz. –

1

Wenn Sie sich entscheiden, ein Makro zu verwenden, dann ein Makro ich empfehlen, die ein einziges Argument:

#define NULL_CHECK(val) if (val == NULL) return SOME_ERROR; 

können Sie dann schreiben:

NULL_CHECK(s1.member1); 
NULL_CHECK(p2->member2); 

Etc. Einer der Vorteile ist, dass Sie die Fehlerberichterstattung oder die Protokollierung genau einbeziehen können, um das erste ungültige Element wie dieses zu identifizieren. Mit einer einzigen zusammengesetzten Bedingung wissen Sie nur, dass mindestens eine von ihnen ungültig ist, aber nicht genau welche.

Wenn Sie mit einer variablen Anzahl von Argumenten umgehen müssen, müssen Sie Boost::Preprocessor untersuchen, was sowohl in C als auch in C++ funktioniert.

0

Nicht, dass ich denke, es ist eine gute Idee, eine return Anweisung innerhalb eines Makros zu verbergen, aber so ein Makro wie geschrieben werden könnte:

#define NULL_CHECK(...)         \ 
    do {             \ 
    void *_p[] = { __VA_ARGS__ };      \ 
    int _i;            \ 
    for (_i = 0; _i < sizeof(_p)/sizeof(*_p); _i++) { \ 
     if (_p[_i] == NULL) {        \ 
     return SOME_ERROR;        \ 
     }             \ 
    }             \ 
    } while(0) 

Grundsätzlich erweitert die varargs in ein Array und Schleife über die Indizes .

+0

Dies ist nicht nur eine unnötig komplizierte Art, etwas sehr einfaches zu tun, es ist auch ineffizienter als der ursprüngliche Code. Ich bin nicht mit Makros für Variablenargumente vertraut, aber ich vermute, dass sie nicht typsicher sind. Wenn ja, ist dieser Code auch viel gefährlicher als der ursprüngliche. – Lundin

+0

@Lundin Um klar zu sein, befürworte ich nicht die Verwendung dieses Codes, aber ich fand es eine kuriose Möglichkeit, den Präprozessor zu verwenden, um Argumente eines variadischen Makros aufzuzählen (was ich denke, ist mehr oder weniger was OP versuchte herauszufinden). Das Makro ist nicht typsicher, aber der generierte Code ist (na ja, so typsicher wie ein 'void *' sein kann). Was Effizienz betrifft, werde ich auf das alte Zitat über vorzeitige Optimierung verzichten. Ich bin skeptisch, dass es in allen außer den extremsten Fällen eine beobachtbare Auswirkung haben würde. – FatalError

+0

Meiner Erfahrung nach führen die meisten Optimierer das Loop-Abrollverfahren nicht aus, es sei denn, Sie fragen speziell danach, da dies zu einer Erhöhung der Programmgröße führen könnte. – Lundin

Verwandte Themen