Ist #define in Industriestandards verboten?

Lesezeit: 11 Minuten

Benutzeravatar von psrag anvesh
psrag anvesh

Ich bin Informatikstudent im ersten Jahr und mein Professor sagte #define ist in den Industriestandards zusammen mit verboten #if, #ifdef, #else, und einige andere Präprozessordirektiven. Er benutzte das Wort „verboten“ wegen unerwarteten Verhaltens.

Ist das richtig? Wenn ja warum?

Gibt es überhaupt Normen, die die Anwendung dieser Richtlinien verbieten?

  • Zuerst habe ich davon gehört. Nein; #define und so weiter sind weit verbreitet. Manchmal zu weit verbreitet, aber definitiv verwendet. Es gibt Stellen, an denen der C-Standard die Verwendung von Makros vorschreibt – Sie können diese nicht einfach vermeiden. Sie könnten die MISRA C-Standards überprüfen; Sie neigen dazu, Dinge zu verbieten, aber ich bin mir ziemlich sicher, dass sogar sie das erkennen #define et al. werden manchmal benötigt.

    – Jonathan Leffler

    28. Dezember 2015 um 15:44 Uhr


  • Eine bessere Faustregel lautet: „Verwende #define nur, wenn nichts anderes ausreicht.“

    – August Karlström

    28. Dezember 2015 um 16:04 Uhr


  • Fragen Sie vielleicht, von wem verboten, in welchen Branchen, welche Veröffentlichungen beziehen sich auf dieses angebliche Verbot usw.?

    – Random832

    28. Dezember 2015 um 16:32 Uhr

  • Ihr Professor ist nicht nur falsch, sie sind komisch falsch. Um dies tatsächlich mit ernstem Gesicht zu sagen, müssten sie null Erfahrung und fast null Kenntnisse in C haben. Diese Person hat keine kaufmännischen Lehren.

    – Leuschenko

    29. Dezember 2015 um 5:53 Uhr

  • @psraganvesh Ist deine Frage vielleicht falsch getaggt? Meinst du C++? Denn in C++ gibt es mehr Möglichkeiten, um ein #define zu „umgehen“. Unrecht hat er trotzdem.

    – Rohr

    29. Dezember 2015 um 6:37 Uhr

Benutzeravatar von Jonathan Leffler
Jonathan Leffler

Zuerst habe ich davon gehört.

Nein; #define und so weiter sind weit verbreitet. Manchmal zu weit verbreitet, aber definitiv verwendet. Es gibt Stellen, an denen der C-Standard die Verwendung von Makros vorschreibt – Sie können diese nicht einfach vermeiden. Zum Beispiel §7.5 Fehler <errno.h> sagt:

Die Makros sind

     EDOM
     EILSEQ
     ERANGE

die zu ganzzahligen konstanten Ausdrücken mit Typ erweitert werden inteindeutig positive Werte, und die für die Verwendung in geeignet sind #if Vorverarbeitungsanweisungen; …

Angesichts dessen ist klar, dass nicht alle Industriestandards die Verwendung der C-Präprozessor-Makrodirektiven verbieten. Es gibt jedoch „Best Practices“- oder „Codierungsrichtlinien“-Standards von verschiedenen Organisationen, die Einschränkungen für die Verwendung des C-Präprozessors vorschreiben, obwohl keine seine Verwendung vollständig verbietet – er ist ein angeborener Bestandteil von C und kann nicht vollständig vermieden werden. Häufig gelten diese Standards für Personen, die in sicherheitskritischen Bereichen arbeiten.

Ein Standard, den Sie überprüfen könnten MISRA C (2012) Standard; das neigt dazu, Dinge zu verbieten, aber selbst das erkennt das an #define et al. werden manchmal benötigt (Abschnitt 8.20, Regeln 20.1 bis 20.14 decken den C-Präprozessor ab).

Die C-Codierungsstandards des NASA GSFC (Goddard Space Flight Center) sagen einfach:

Makros sollten nur bei Bedarf verwendet werden. Die übermäßige Verwendung von Makros kann das Lesen und Verwalten von Code erschweren, da sich der Code nicht mehr wie Standard-C liest oder verhält.

Die Diskussion nach dieser einleitenden Erklärung veranschaulicht die akzeptable Verwendung von Funktionsmakros.

Das CERT C-Codierungsstandard enthält eine Reihe von Richtlinien zur Verwendung des Präprozessors und impliziert, dass Sie die Verwendung des Präprozessors minimieren sollten, verbietet seine Verwendung jedoch nicht.

Stroustrup würde den Präprozessor in C++ gerne irrelevant machen, aber das ist noch nicht geschehen. Wie Peter anmerkt, sind einige C++-Standards, wie z JSF AV C++-Codierungsstandards (Joint Strike Fighter, Luftfahrzeug) von ca. 2005 schreiben eine minimale Verwendung des C-Präprozessors vor. Im Wesentlichen beschränken die JSF AV C++-Regeln es auf #include und die #ifndef XYZ_H / #define XYZ_H / … / #endif Tanz, der mehrere Einschlüsse eines einzelnen Headers verhindert. C++ hat einige Optionen, die in C nicht verfügbar sind – insbesondere eine bessere Unterstützung für typisierte Konstanten, die dann an Stellen verwendet werden können, an denen C ihre Verwendung nicht zulässt. Siehe auch static const vs #define vs enum für eine Diskussion der dortigen Probleme.

Es ist eine gute Idee, die Verwendung des Präprozessors zu minimieren – er wird oft mindestens so oft missbraucht wie er verwendet wird (siehe die Schub Präprozessor ‘Bibliothek’ für Veranschaulichungen, wie weit Sie mit dem C-Präprozessor gehen können).

Zusammenfassung

Der Präprozessor ist ein integraler Bestandteil von C und #define und #if usw. lassen sich nicht ganz vermeiden. Die Aussage des Professors in der Frage ist nicht allgemeingültig: #define ist in den Industriestandards zusammen mit verboten #if, #ifdef, #elseund ein paar andere Makros ist bestenfalls eine Übertreibung, könnte aber mit ausdrücklichem Verweis auf bestimmte Industriestandards unterstützt werden (aber die fraglichen Standards beinhalten nicht ISO/IEC 9899:2011 – den C-Standard).


Beachten Sie, dass David Hammen Informationen zu einem bestimmten C-Codierungsstandard bereitgestellt hat – dem JPL C-Codierungsstandard – das viele Dinge verbietet, die viele Leute in C verwenden, einschließlich der Einschränkung der Verwendung des C-Präprozessors (und der Verwendung der dynamischen Speicherzuweisung und des Verbots der Rekursion) – lesen Sie es, um zu sehen, warum, und entscheiden Sie, ob diese Gründe relevant sind für dich).

  • Einige der MISRA-Regeln erfordern/raten zu bestimmten Einschränkungen bei der Verwendung von Makros, aber sie sind ziemlich vernünftig. Ich war tatsächlich überrascht von ihrer Freizügigkeit. Eben #define MAX(a,b) ((a>b)?(a):(b)) ist in Ordnung, trotz seiner potenziellen Gefahren.

    – Sneftel

    28. Dezember 2015 um 15:57 Uhr


  • @Sneftel: Danke. Ich habe nicht alle MISRA-Regeln gelesen (es steht auf meiner “To Do”-Liste, aber nicht mit hoher Priorität), aber es war eine mögliche Quelle für “Industriestandards”, die dem, was Sie tun können, im Vergleich zu dem, was Sie tun können, Grenzen setzt die Norm erlaubt.

    – Jonathan Leffler

    28. Dezember 2015 um 16:01 Uhr

  • Es gibt eine Reihe von Richtlinien oder Standards für sicherheitskritische oder unternehmenskritische Entwicklung, die die Verwendung von Funktionsmakros sowohl in C als auch in C++ verbieten.

    – Petrus

    28. Dezember 2015 um 16:04 Uhr

  • @Peter: kannst du ein konkretes Beispiel geben? MISRA entspricht nicht dem, was Sneftel sagt, und meinem minimalen Scannen. Ich habe gerade die C-Codierungsstandard-Richtlinien des NASA GSFC (Goddard Space Flight Center) überprüft, und es heißt: Makros sollten nur bei Bedarf verwendet werden. Die übermäßige Verwendung von Makros kann das Lesen und Verwalten von Code erschweren, da sich der Code nicht mehr wie Standard-C liest oder verhält. fährt aber mit einem Beispiel eines Funktionsmakros fort.

    – Jonathan Leffler

    28. Dezember 2015 um 16:09 Uhr


  • Lesen 7.5 Fehler im C-Standard. Es erfordert die Verwendung von Makros. Buchstäblich.

    – Andreas Henle

    28. Dezember 2015 um 16:42 Uhr

Nein, die Verwendung von Makros ist nicht verboten.

In der Tat, die Verwendung von #include Guards in Header-Dateien ist eine gängige Technik, die oft obligatorisch ist und durch akzeptierte Codierungsrichtlinien gefördert wird. Manche Leute behaupten das #pragma once ist eine Alternative dazu, aber das Problem ist das #pragma once – per Definition, da Pragmas ein Hook sind, der vom Standard für Compiler-spezifische Erweiterungen bereitgestellt wird – kein Standard ist, auch wenn es von einer Reihe von Compilern unterstützt wird.

Allerdings gibt es eine Reihe von Branchenrichtlinien und empfohlenen Praktiken, die aktiv von der Verwendung von anderen Makros abraten als #include Wachen wegen der Probleme, die Makros einführen (Nichteinhaltung des Geltungsbereichs usw.). In der C++-Entwicklung ist der Einsatz von Makros noch stärker verpönt als in der C-Entwicklung.

Von der Nutzung abzuraten ist nicht gleichbedeutend mit einem Verbot, da eine legitime Nutzung – beispielsweise durch Dokumentation einer Begründung – weiterhin möglich ist.

Benutzeravatar von John Bode
Johannes Bode

Einige Codierungsstandards können die Verwendung von entmutigen oder sogar verbieten #define erschaffen funktionsähnliche Makros die Argumente nehmen, wie

#define SQR(x) ((x)*(x))

weil a) solche Makros nicht typsicher sind und b) jemand es tun wird zwangsläufig schreiben SQR(x++)was schlechtes Juju ist.

Einige Standards können die Verwendung von entmutigen oder verbieten #ifdefs für die bedingte Kompilierung. Der folgende Code verwendet beispielsweise die bedingte Kompilierung, um a korrekt auszugeben size_t Wert. Zum C99 und später verwenden Sie die %zu Konvertierungsbezeichner; zum C89 und früher verwenden Sie %lu und wandeln Sie den Wert in um unsigned long:

#if __STDC_VERSION__ >= 199901L
#  define SIZE_T_CAST
#  define SIZE_T_FMT "%zu"
#else
#  define SIZE_T_CAST (unsigned long)
#  define SIZE_T_FMT "%lu"
#endif
...
printf( "sizeof foo = " SIZE_T_FMT "\n", SIZE_T_CAST sizeof foo );

Einige Normen kann verlangen, dass Sie stattdessen das Modul zweimal implementieren, einmal für C89 und früher, einmal für C99 und höher:

/* C89 version */
printf( "sizeof foo = %lu\n", (unsigned long) sizeof foo );

/* C99 version */
printf( "sizeof foo = %zu\n", sizeof foo );

und dann lassen Machen (oder Ameise, oder welches Build-Tool auch immer Sie verwenden) kümmern sich um das Kompilieren und Verknüpfen der richtigen Version. Für dieses Beispiel wäre das ein lächerlicher Overkill, aber ich habe Code gesehen, der ein unauffindbares Rattennest war #ifdefist das sollte haben diesen bedingten Code in separate Dateien ausgelagert.

Mir ist jedoch kein Unternehmen oder Branchenverband bekannt, der dies getan hat verboten die Verwendung von Präprozessor-Anweisungen geradezu.

Benutzeravatar von Andrew Henle
Andreas Henle

Makros können nicht “gesperrt” werden. Die Aussage ist Unsinn. Buchstäblich.

Zum Beispiel Abschnitt 7.5 Fehler <errno.h> des C-Standard erfordert die Verwendung von Makros:

1 Die Kopfzeile <errno.h> definiert mehrere Makros, die sich alle auf das Melden von Fehlerbedingungen beziehen.

2 Die Makros sind

EDOM
EILSEQ
ERANGE

die zu ganzzahligen konstanten Ausdrücken mit Typ erweitert werden inteindeutig positive Werte, und die für die Verwendung in geeignet sind #if Vorverarbeitungsanweisungen; und

errno

die zu einem änderbaren lvalue erweitert wird, der einen Typ hat int und lokale Speicherdauer des Threads, deren Wert von mehreren Bibliotheksfunktionen auf eine positive Fehlerzahl gesetzt wird. Wenn eine Makrodefinition unterdrückt wird, um auf ein tatsächliches Objekt zuzugreifen, oder ein Programm einen Bezeichner mit dem Namen definiert errnoist das Verhalten undefiniert.

Makros sind also nicht nur a erforderlich Teil von C, in einigen Fällen führt ihre Nichtverwendung zu undefiniertem Verhalten.

Benutzeravatar von Viktor Toth
Viktor Tot

Nein, #define ist nicht verboten. Missbrauch von #definekann jedoch verpönt sein.

Sie können zum Beispiel verwenden

#define DEBUG

in Ihrem Code, damit Sie später Teile Ihres Codes für die bedingte Kompilierung verwenden können #ifdef DEBUG, nur für Debug-Zwecke. Ich glaube nicht, dass jemand, der bei klarem Verstand ist, so etwas verbieten möchte. Makros definiert mit #define werden auch häufig in portablen Programmen verwendet, um die Kompilierung von plattformspezifischem Code zu aktivieren/deaktivieren.

Wenn Sie jedoch etwas wie verwenden

#define PI 3.141592653589793

Ihr Lehrer kann zu Recht darauf hinweisen, dass es viel besser ist, zu erklären PI als Konstante mit entsprechendem Typ, z. B.

const double PI = 3.141592653589793;

da es dem Compiler ermöglicht, Typprüfungen durchzuführen, wenn PI wird genutzt.

In ähnlicher Weise (wie oben von John Bode erwähnt) kann die Verwendung von funktionsähnlichen Makros abgelehnt werden, insbesondere in C++, wo Templates verwendet werden können. Also statt

#define SQ(X) ((X)*(X))

erwägen zu verwenden

double SQ(double X) { return X * X; }

oder, in C++, noch besser,

template <typename T>T SQ(T X) { return X * X; }

Auch hier besteht die Idee darin, dass Sie durch die Verwendung der Funktionen der Sprache anstelle des Präprozessors dem Compiler ermöglichen, check einzugeben und (möglicherweise) auch besseren Code zu generieren.

Sobald Sie genügend Programmiererfahrung haben, wissen Sie genau, wann es angebracht ist, es zu verwenden #define. Bis dahin halte ich es für eine gute Idee, dass Ihr Lehrer bestimmte Regeln und Codierungsstandards auferlegt, aber vorzugsweise sollten sie selbst die Gründe kennen und erklären können. Ein pauschales Verbot #define ist unsinnig.

Benutzeravatar von mikedu95
mikedu95

Das ist völlig falsch, Makros werden in C stark verwendet. Anfänger verwenden sie oft schlecht, aber das ist kein Grund, sie aus der Industrie zu verbannen. Eine klassische schlechte Verwendung ist #define succesor(n) n + 1. Wenn Sie erwarten 2 * successor(9) 20 zu geben, dann liegen Sie falsch, denn dieser Ausdruck wird übersetzt als 2 * 9 + 1 dh 19 nicht 20. Verwenden Sie Klammern, um das erwartete Ergebnis zu erhalten.

Benutzeravatar von luis.espinal
luis.espinal

Nein. Es ist nicht verboten. Und um ehrlich zu sein, es ist unmöglich, nicht-trivialen Multi-Plattform-Code ohne sie zu erstellen.

  • Multi-Plattform und Cross-Compiler, würde ich sagen 🙂

    – Andrea Corbellini

    28. Dezember 2015 um 16:13 Uhr

  • Ach, tatsächlich? Wie erstellen Sie ein Threading-Framework, das über POSIX-Threads und/oder über die Windows-API arbeitet, ohne sich auf Shims von Drittanbietern (a-la Cygwin oder Mingw) zu verlassen? Wir sprechen nicht nur über dasselbe Betriebssystem, mehrere Hardware, sondern mehrere Betriebssysteme oder Compiler-Anbieter. Haben Sie jemals versucht, ein System zu unterstützen, das beispielsweise auf Linux und Integrity-OS ausgerichtet ist, die beide unterschiedliche Compiler erfordern? Neg-rep alles was du willst. Tatsachen auf dem schmutzigen Boden werden sich trotzdem nicht ändern.

    – luis.espinal

    28. Dezember 2015 um 16:19 Uhr


  • Ich stimme dir zu 100% zu. Ich habe gerade hinzugefügt, dass der Präprozessor auch beim Schreiben von Cross-Compiler-Code nützlich ist.

    – Andrea Corbellini

    28. Dezember 2015 um 16:23 Uhr

1415920cookie-checkIst #define in Industriestandards verboten?

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

Privacy policy