Ist #define in Industriestandards verboten?

68

Ich bin ein erstes Jahr Informatik - Student und mein Professor sagte , #defineist in den Industriestandards verboten zusammen mit #if, #ifdef, #else, und ein paar andere Präprozessordirektiven. Er benutzte das Wort "verboten" wegen unerwarteten Verhaltens.

Ist das richtig? Wenn ja warum?

Gibt es tatsächlich Standards, die die Verwendung dieser Richtlinien verbieten?

psrag anvesh
quelle
62
Zuerst habe ich davon gehört. Nein; #defineund 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 - diese können Sie nicht einfach vermeiden. Sie können die MISRA C-Standards überprüfen. Sie neigen dazu, Dinge zu verbieten, aber ich bin mir ziemlich sicher, dass selbst sie erkennen, dass #defineet al manchmal benötigt werden.
Jonathan Leffler
18
Eine bessere Faustregel lautet: "Verwenden Sie #define nur, wenn nichts anderes ausreicht."
August Karlstrom
21
Vielleicht fragen, von wem verboten, in welchen Branchen, welche Veröffentlichungen beziehen sich auf dieses angebliche Verbot usw.?
Random832
33
Ihr Professor ist nicht nur falsch, sie sind komisch falsch. Um dies tatsächlich mit ernstem Gesicht zu sagen, müssten sie keine Erfahrung und fast kein Wissen über C haben. Diese Person hat keinen kaufmännischen Unterricht.
Leushenko
4
@psraganvesh Ist Ihre Frage möglicherweise falsch markiert? Meinst du C ++? Denn in C ++ gibt es mehr Möglichkeiten, um eine #Definition zu "umgehen". Er liegt trotzdem falsch.
Pipe

Antworten:

141

Zuerst habe ich davon gehört.

Nein; #defineund 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 - diese können Sie nicht einfach vermeiden. Zum Beispiel sagt §7.5 Fehler<errno.h> :

Die Makros sind

die sich zu ganzzahligen konstanten Ausdrücken mit Typ intund unterschiedlichen positiven Werten erweitern und für die Verwendung in #ifVorverarbeitungsanweisungen geeignet sind ; …

Angesichts dessen ist klar, dass nicht alle Industriestandards die Verwendung der Makroanweisungen für C-Präprozessoren verbieten. Es gibt jedoch Standards für bewährte Verfahren oder Codierungsrichtlinien von verschiedenen Organisationen, die Beschränkungen für die Verwendung des C-Präprozessors vorschreiben, obwohl keiner seine Verwendung vollständig verbietet - er ist ein angeborener Teil von C und kann nicht vollständig vermieden werden. Diese Standards gelten häufig für Personen, die in sicherheitskritischen Bereichen arbeiten.

Ein Standard, den Sie überprüfen können, ist der MISRA C (2012) -Standard. das neigt dazu, Dinge zu verbieten, aber selbst das erkennt, dass #definemanchmal et al. benötigt werden (Abschnitt 8.20, Regeln 20.1 bis 20.14 behandeln den C-Präprozessor).

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

Makros sollten nur bei Bedarf verwendet werden. Übermäßiger Gebrauch von Makros kann das Lesen und Verwalten von Code erschweren, da der Code nicht mehr wie Standard C liest oder sich so verhält.

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

Der 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, seine Verwendung jedoch nicht verbieten.

Stroustrup möchte den Präprozessor in C ++ irrelevant machen, aber das ist noch nicht geschehen. Wie Peter bemerkt , schreiben einige C ++ - Standards, wie die JSF AV C ++ - Codierungsstandards ( Joint Strike Fighter, Luftfahrzeug ) von ca. 2005, eine minimale Verwendung des C-Präprozessors vor. Im Wesentlichen beschränken sich die JSF AV C ++ - Regeln auf #includeund #ifndef XYZ_H/ #define XYZ_H/… / #endifdance, wodurch mehrere Einschlüsse eines einzelnen Headers verhindert werden. C ++ verfügt über 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 die Verwendung nicht zulässt. Siehe auch static constvs #definevsenum für eine Diskussion der dortigen Probleme.

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

Zusammenfassung

Der Präprozessor ist ein integraler Bestandteil von C #defineund #ifusw. kann nicht vollständig vermieden werden. Die Erklärung des Professor in der Frage ist nicht allgemein gültig: #definewird zusammen mit den Industrie - Standards verboten #if, #ifdef, #else, und ein paar andere Makros ist eine Over-Anweisung am besten, aber vielleicht mit ausdrücklicher Bezugnahme auf bestimmte Industriestandards erträglich sein (aber Die fraglichen Normen enthalten nicht ISO / IEC 9899: 2011 (die C-Norm).


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

Jonathan Leffler
quelle
3
Einige der MISRA-Regeln erfordern / empfehlen bestimmte Einschränkungen bei der Verwendung von Makros, sind jedoch ziemlich allgemein sinnvoll. Eigentlich war ich von ihrer Zulässigkeit überrascht. Auch #define MAX(a,b) ((a>b)?(a):(b))ist in Ordnung, trotz seiner möglichen Gefahren.
Sneftel
1
@Sneftel: Danke. Ich habe nicht alle MISRA-Regeln gelesen (sie stehen auf meiner "To Do" -Liste, haben aber keine hohe Priorität), aber es war eine mögliche Quelle für "Industriestandard", die Ihre Möglichkeiten im Vergleich zu was einschränkt Der Standard erlaubt.
Jonathan Leffler
1
Es gibt eine Reihe von Richtlinien oder Standards für die sicherheitskritische oder geschäftskritische Entwicklung, die die Verwendung von Funktionsmakros sowohl in C als auch in C ++ verbieten.
Peter
1
@ Peter: Kannst du ein konkretes Beispiel geben? MISRA entspricht nicht dem, was Sneftel sagt, und meinem minimalen Scannen. Ich habe gerade die Richtlinien des C-Codierungsstandards der GSFC (Goddard Space Flight Center) der NASA überprüft und es heißt dort: Makros sollten nur bei Bedarf verwendet werden. Übermäßiger Gebrauch von Makros kann das Lesen und Verwalten von Code erschweren, da der Code nicht mehr wie Standard C liest oder sich verhält, sondern mit einem Beispiel für ein Funktionsmakro fortfährt.
Jonathan Leffler
5
Lesen Sie 7.5 Fehler im C-Standard. Es erfordert die Verwendung von Makros. Buchstäblich.
Andrew Henle
33

Nein, die Verwendung von Makros ist nicht verboten.

Tatsächlich ist die Verwendung von #includeSchutzvorrichtungen in Header-Dateien eine gängige Technik, die häufig obligatorisch ist und durch anerkannte Codierungsrichtlinien gefördert wird. Einige Leute behaupten, dass dies #pragma onceeine Alternative dazu ist, aber das Problem ist, dass #pragma once- per Definition, da Pragmas ein Haken sind, der vom Standard für compilerspezifische Erweiterungen bereitgestellt wird - nicht Standard ist, selbst wenn er von einer Reihe von Compilern unterstützt wird.

Es gibt jedoch eine Reihe von Branchenrichtlinien und empfohlenen Praktiken, die die Verwendung von Makros außer #includeWachen aufgrund der Probleme, die Makros mit sich bringen (ohne Berücksichtigung des Umfangs usw.), aktiv unterbinden. In der C ++ - Entwicklung wird die Verwendung von Makros noch stärker verpönt als in der C-Entwicklung.

Von der Verwendung von etwas abzuraten ist nicht dasselbe wie es zu verbieten, da es immer noch möglich ist, es rechtmäßig zu verwenden - zum Beispiel durch Dokumentation einer Begründung.

Peter
quelle
30

Einige Codierungsstandards entmutigen oder sogar verbieten die Verwendung von #defineerstellen Funktionsmakros , die Argumente, wie

weil a) solche Makros nicht typsicher sind und b) unweigerlich jemand schreibt SQR(x++), was schlecht ist, Juju.

Einige Standards können die Verwendung von #ifdefs für die bedingte Kompilierung verhindern oder verbieten . Der folgende Code verwendet beispielsweise die bedingte Kompilierung, um einen size_tWert ordnungsgemäß auszudrucken . Für C99 und höher verwenden Sie den %zuKonvertierungsspezifizierer. Für C89 und früher verwenden Sie %luden Wert und wandeln ihn in Folgendes um unsigned long:

Einige Standards schreiben möglicherweise vor , dass Sie das Modul stattdessen zweimal implementieren, einmal für C89 und früher, einmal für C99 und höher:

Lassen Sie dann Make (oder Ant oder das von Ihnen verwendete Build-Tool) das Kompilieren und Verknüpfen der richtigen Version durchführen. Für dieses Beispiel , die lächerlich übertrieben wäre, aber ich habe Code gesehen , dass ein unauffindbar Rattennest von war #ifdefs, der sollte die bedingte Code in separate Dateien ausgeklammert hatten.

Mir sind jedoch keine Unternehmen oder Branchengruppen bekannt, die die Verwendung von Präprozessoranweisungen vollständig verboten haben .

John Bode
quelle
16

Makros können nicht "gebannt" werden. Die Aussage ist Unsinn. Buchstäblich.

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

1 Der Header <errno.h>definiert mehrere Makros, die sich alle auf die Meldung von Fehlerzuständen beziehen.

2 Die Makros sind

die sich zu ganzzahligen konstanten Ausdrücken mit Typ intund unterschiedlichen positiven Werten erweitern und für die Verwendung in #ifVorverarbeitungsanweisungen geeignet sind ; und

Dies erweitert sich zu einem modifizierbaren Wert mit intlokaler Speicherdauer für Typ und Thread, dessen Wert von mehreren Bibliotheksfunktionen auf eine positive Fehlernummer gesetzt wird. Wenn eine Makrodefinition unterdrückt wird, um auf ein tatsächliches Objekt zuzugreifen, oder ein Programm einen Bezeichner mit dem Namen definiert errno, ist das Verhalten undefiniert.

Makros sind also nicht nur ein erforderlicher Bestandteil von C, in einigen Fällen führt ihre Nichtverwendung zu undefiniertem Verhalten.

Andrew Henle
quelle
Wenn Sie sie nicht verwenden, führt dies zu einem undefinierten Verhalten , das nicht genau dem entspricht, was der Text sagt (oder ich falsch interpretiere / falsch interpretiere). Es heißt, es gibt UB, wenn entweder "eine Makrodefinition unterdrückt wird" oder "ein Bezeichner namens errno definiert ist" und ich nicht sehe, wie Sie den Link daraus zu "keine Makros verwenden" ziehen. Im Gegenteil, diese beiden Aktionen (Unterdrücken / Definieren) sind typische Dinge, die Sie tun, wenn Sie Makros verwenden, nicht wenn Sie sie nicht verwenden?
stijn
1
@stijn - Wie würden Sie zugreifen, errnoohne das Makro zu verwenden, ohne UB aufzurufen? Der Standard sagt eindeutig, dass errnoes sich um ein Makro handelt, und es besagt eindeutig, dass das errnoMakro unterdrückt oder auf andere Weise Ihre eigenen errnoErgebnisse in UB definiert werden. Und wie kann man im Allgemeinen robusten Code schreiben, ohne ihn zu verwenden errno? Einige Systemaufrufe können weiterhin unterbrochen werden und einen Fehler mit errnoset to zurückgeben, EINTRselbst wenn alle Ihre Signalflags SA_RESTARTgesetzt sind. Ergo, wenn Sie verwenden errno, können Sie nicht ohne Makros codieren, es sei denn, Sie rufen UB auf.
Andrew Henle
Ja, das ist alles wahr, und ich befürworte nicht, dass man keine Makros verwenden sollte, und definitiv nicht, dass man keine Errno verwenden sollte, sondern nur Nitpicking, aber Ihr Kommentar imo hat immer noch keinen persönlichen Beweis dafür, dass Sie keine Makros in Ihren eigenen verwenden Code führt irgendwie zu UB. (Beachten Sie Ihren letzten Satz " wenn Sie errno verwenden", also erstens, wenn Sie nicht alles in Ordnung sind (na ja, irgendwie :) und zweitens, selbst wenn Sie errno verwenden, verwenden Sie tatsächlich bereits Makros und müssten es immer noch Verwenden Sie mehr Makros, um die UB aufzurufen, also werden sie auch hier nicht verwendet
am
@stijn Meine Antwort besagt , dass Makros nicht nur ein erforderlicher Bestandteil von C sind, sondern in einigen Fällen zu undefiniertem Verhalten führen, wenn sie nicht verwendet werden. In Abschnitt 7.5 werden Makros eindeutig zu einem erforderlichen Bestandteil der C-Sprache. Und wenn Sie versuchen, errnoohne das erforderliche Makro zu verwenden, rufen Sie UB auf. Klar?
Andrew Henle
1
@Andew: Ich glaube, stijns Argument ist, dass es einen Unterschied zwischen "nicht errno verwenden" und "errno ohne Makros verwenden" gibt, und daher ist es nicht "nicht verwenden", was die UB verursacht, sondern sie falsch zu verwenden. Der Nitpick ist bei den Engländern, nicht beim C.
Ray
15

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

Zum Beispiel können Sie verwenden

#define DEBUG

in Ihrem Code, damit Sie später Teile Ihres Codes für die bedingte Kompilierung #ifdef DEBUGnur für Debug-Zwecke festlegen können. Ich glaube nicht, dass jemand, der bei klarem Verstand ist, so etwas verbieten möchte. Mit definierte Makros #definewerden auch häufig in tragbaren Programmen verwendet, um die Kompilierung von plattformspezifischem Code zu aktivieren / deaktivieren.

Wenn Sie jedoch so etwas verwenden

#define PI 3.141592653589793

Ihr Lehrer kann zu Recht darauf hinweisen, dass es viel besser ist, PIeine Konstante mit dem entsprechenden Typ zu deklarieren , z.

const double PI = 3.141592653589793;

da es dem Compiler ermöglicht, die Typprüfung durchzuführen, wenn sie PIverwendet wird.

In ähnlicher Weise (wie oben von John Bode erwähnt) kann die Verwendung von funktionsähnlichen Makros abgelehnt werden, insbesondere in C ++, wo Vorlagen 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; }

Wieder einmal besteht die Idee darin, dass Sie dem Compiler durch die Verwendung der Funktionen der Sprache anstelle des Präprozessors erlauben, die Prüfung zu tippen und (möglicherweise) besseren Code zu generieren.

Sobald Sie über ausreichende Programmiererfahrung verfügen, wissen Sie genau, wann die Verwendung angemessen ist #define. Bis dahin halte ich es für eine gute Idee, wenn Ihr Lehrer bestimmte Regeln und Kodierungsstandards auferlegt, aber vorzugsweise sollten sie selbst die Gründe kennen und erklären können. Ein generelles Verbot #defineist unsinnig.

Viktor Toth
quelle
12

Das ist völlig falsch, Makros werden in C häufig 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, liegen Sie falsch, da dieser Ausdruck als 2 * 9 + 119 und nicht als 20 übersetzt wird. Verwenden Sie Klammern, um das erwartete Ergebnis zu erhalten.

mikedu95
quelle
2
Ich bin nicht sicher, ob das Beispiel die falsche Verwendung eines Anfängers eindeutig rechtfertigt.
psrag anvesh
1
Es ist wahr, jeder sollte wissen, dass Makros auf einzelne Token-Äquivalente erweitert werden müssen, was so ziemlich Klammern für die Erweiterung #define successor(n) ((n) + 1)
vorschreibt
11

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

luis.espinal
quelle
2
Multi-Plattform und Cross-Compiler, würde ich sagen :)
Andrea Corbellini
Ja wirklich? Wie erstellen Sie ein Threading-Framework, das über POSIX-Threads und / oder über die Windows-API ausgeführt wird, ohne sich auf Shims von Drittanbietern (a-la-cygwin oder mingw) zu verlassen? Wir sprechen nicht nur über Same-OS, mehrere Hardware, sondern auch über mehrere Betriebssysteme oder Compiler-Anbieter. Haben Sie jemals versucht, ein System zu unterstützen, das beispielsweise auf Linux und Integrity-OS ausgerichtet ist und für die beide unterschiedliche Compiler erforderlich sind? Neg-rep alles was du willst. Die Fakten auf dem schmutzigen Boden werden sich trotzdem nicht ändern.
Luis.espinal
8
Ich stimme Ihnen zu 100% zu. Ich habe nur hinzugefügt, dass der Präprozessor auch beim Schreiben von Cross-Compiler-Code nützlich ist.
Andrea Corbellini
8

Nein, Ihr Professor liegt falsch oder Sie haben etwas falsch gehört.

#defineist ein Präprozessor-Makro, und Präprozessor-Makros werden für die bedingte Kompilierung und einige Konventionen benötigt, die nicht einfach in der C-Sprache erstellt wurden. Beispielsweise wurde in einem neueren C-Standard, nämlich C99, die Unterstützung für Boolesche Werte hinzugefügt. Aber es wird nicht "native" von der Sprache unterstützt, sondern von Präprozessoren #define. Siehe diesen Verweis auf stdbool.h

Superlokkus
quelle
2
er sagte zweimal, nachdem ich ihn zum zweiten Mal gefragt hatte: "In der Branche wegen undefinierten Verhaltens verboten", weil ich das nirgendwo anders gehört habe
psrag anvesh
undefiniertes Verhalten? : |
Andrea Corbellini
3
@psraganvesh Undefiniertes Verhalten wird eher beispielsweise durch *NULLoder char foo[2]; foo[2];alle Programmierfehler verursacht. Um besser zu wissen, was undefiniertes Verhalten ist, empfehle ich Folgendes
Superlokkus
2
@psraganvesh Banning Makros führen würde in undefinierten Verhalten pro C - Standard. Siehe meine Antwort bezüglich errno- der Standard besagt ausdrücklich, dass die errnoNichtverwendung des Makros zu undefiniertem Verhalten führt.
Andrew Henle
1
@psraganvesh Wenn Ihr Lehrer tatsächlich gesagt hat, dass #define, #if usw. zu undefiniertem Verhalten führt, sollte er keine Klasse über C unterrichten. Wahrscheinlich hat er noch nie Code in C geschrieben und sich selbst um diesen Job betrogen. Ich würde darüber nachdenken, dies mit jemandem weiter oben zu besprechen.
Pipe
6

Makros werden in GNU Land C ziemlich häufig verwendet, und ohne bedingte Präprozessorbefehle gibt es keine Möglichkeit, mehrere Einschlüsse derselben Quelldateien ordnungsgemäß zu verarbeiten, sodass sie mir als wesentliche Sprachfunktionen erscheinen.

Vielleicht ist Ihre Klasse tatsächlich in C ++, was trotz des Versäumnisses vieler Leute von C unterschieden werden sollte, da es eine andere Sprache ist und ich dort nicht für Makros sprechen kann. Oder vielleicht meinte der Professor, er verbiete sie in seiner Klasse. Ich bin mir jedenfalls sicher, dass die SO-Community daran interessiert sein würde, über welchen Standard er spricht, da ich mir ziemlich sicher bin, dass alle C-Standards die Verwendung von Makros unterstützen.

Daniel Farrell
quelle
3
Lol wie kann ich nicht wissen, welche Klasse ich höre
? Er
2
Makros sind auch in C ++ erforderlich. Zum Beispiel gibt es keine andere Möglichkeit (die ich kenne), Header Guards ( #ifndef HEADER_H #define HEADER_H ... #endif)
einzufügen
1
@R_Kapp hast du noch nie gehört #pragma once? Schauen Sie auf jeden Fall nach - es hat es noch nicht in den Standard geschafft, aber es wird von jedem Anbieter (GCC, Clang, EDG, MSVC, Intel, Green Hills, ARM, ...) unterstützt und verringert die Wahrscheinlichkeit, dumme Tippfehler zu machen, erheblich #ifndef FOO_H #define FOOHoder #ifdef FOO_H #define FOO_Hoder dasselbe Makro in zwei verschiedenen .h-Dateien verwenden. (Es verbessert auch die Kompilierungszeiten und beseitigt heilige Kriege um den Abstand und das Einrücken von #ifndefWachen im Stil.) Die bedingte Kompilierung hat zwar ihre Verwendung, aber "arme Männer #pragma once" gehören nicht dazu.
Quuxplusone
2
@Quuxplusone #pragma wird es mit ziemlicher Sicherheit nicht in den C-Standard schaffen, weil es ein Pragma ist. Pragmas sind für implementierungsdefiniertes Verhalten reserviert. Wenn Sie es also zum Standard hinzufügen, wird jeder Compiler, der es verwendet hat, auf eine Weise beschädigt, die diesem neuen vermeintlichen Standard nicht entspricht. Daher würde ich sagen, dass es am besten vermieden wird, wenn möglich, und dass dies eine sehr gültige Verwendung für #ifndef
Vality
2
Es ist mehr, etwas in den Standard aufzunehmen, als jemanden, der einen Vorschlag schreibt. Der Sinn von Pragmas - sowohl in den C- als auch in den C ++ - Standards - besteht darin, einen Haken für das implementierungsdefinierte Verhalten bereitzustellen, und Implementierungen können jede Verwendung von ignorieren #pragma. Es ist daher einfach eine Fantasie zu behaupten, dass jedes Pragma jemals standardisiert wird - der Begriff steht völlig im Widerspruch zu dem, was Pragmas sind. Die Tatsache, dass mehrere Anbieter einige ihrer herstellerspezifischen Funktionen standardmäßig falsch darstellen, macht dies nicht möglich.
Peter
6

Im Gegensatz zu allen bisherigen Antworten ist die Verwendung von Präprozessor-Direktiven im hochzuverlässigen Computing häufig verboten. Hiervon gibt es zwei Ausnahmen, deren Verwendung in solchen Organisationen vorgeschrieben ist. Dies sind die #includeDirektive und die Verwendung eines Include-Schutzes in einer Header-Datei. Diese Art von Verboten ist in C ++ wahrscheinlicher als in C.

Hier nur ein Beispiel: 16.1.1 Verwenden Sie den Präprozessor nur zum Implementieren von Include-Guards und zum Einschließen von Header-Dateien mit Include-Guards .

Ein weiteres Beispiel, diesmal für C statt C ++: JPL Institutional Coding Standard für die Programmiersprache C . Dieser C-Codierungsstandard geht nicht ganz so weit, die Verwendung des Präprozessors vollständig zu verbieten, kommt aber nahe. Insbesondere heißt es

Regel 20 (Verwendung des Präprozessors) Die Verwendung des C-Präprozessors ist auf die Aufnahme von Dateien und einfache Makros beschränkt. [Zehnerpotenz Regel 8].


Ich kann diese Standards weder dulden noch entschlüsseln. Aber zu sagen, dass sie nicht existieren, ist lächerlich.

David Hammen
quelle
Und die Frage ist mit C.
jxh
@jxh - Und ich habe in Organisationen gearbeitet, in denen solche Verbote bestanden, und zwar in Bezug auf C und nicht in Bezug auf C ++. Ich persönlich mochte es nicht, aber sie existieren.
David Hammen
Ja, die Konsequenz ist, dass ein standardisierter Mechanismus zur Codegenerierung entfernt wird und Hacks mithilfe von Skriptsprachen den richtigen Quellcode generieren, anstatt eine bedingte Kompilierung durchzuführen.
jxh
6
Dass es mindestens eine Umgebung gibt, in der Makros verboten sind, bedeutet keineswegs, dass sie branchenweit verboten sind. Die vorhandenen Antworten sind also weder falsch noch "lächerlich".
Leichtigkeitsrennen im Orbit
2
@LightnessRacesinOrbit - Ich habe nicht gesagt, dass sie in der gesamten Branche verboten sind. Die am besten bewertete (und IMNHO fälschlicherweise akzeptierte) Antwort lautet "Zuerst habe ich davon gehört", zusammen mit mehreren anderen Antworten, die etwas Ähnliches aussagen. Was wir hier haben, ist ein Professor, der möglicherweise nur eine Branche kennt, in der die Verwendung des Präprozessors stark eingeschränkt ist, ein Student, der höchstwahrscheinlich falsch interpretiert hat, was der Professor gesagt hat, und eine Reihe von Antworten, die diese falsch interpretierte Frage überinterpretiert haben . Dies ist nicht nur ein XY-Problem. Es ist ein XYZW-Problem.
David Hammen
2

Wenn Ihr C-Code mit C ++ - Code zusammenarbeiten soll, müssen Sie Ihre extern sichtbaren Symbole, z. B. Funktionsdeklarationen, im extern "C"Namespace deklarieren . Dies erfolgt häufig mithilfe der bedingten Kompilierung:

jxh
quelle
Dies könnte jedoch #include "c++/header.h"im C ++ - Code geschehen, in dem die Datei Folgendes "c++/header.h"enthält: extern "C" { / #include "c/header.h" / }(mit Solo-Schrägstrichen, die Zeilenumbrüche anzeigen - und die Auswahl der Unterverzeichnisnamen ist natürlich weitgehend willkürlich), wodurch eine bedingte Kompilierung auf Kosten von a vermieden würde zusätzliche Datei. Ich stimme zu, was Sie zeigen, ist das, was am häufigsten verwendet wird (ich benutze es selbst). Aber es ist eigentlich nicht notwendig, wenn Sie die Dinge richtig eingerichtet haben.
Jonathan Leffler
Die bedingte Kompilierung kann durch ein Makefile ersetzt werden, das je nach den Bedingungen verschiedene Quelldateien auswählt. Es macht es nicht zu einer besseren Lösung, es erfüllt nur die "Nein #if" -Anforderung. Zwei Header-Dateien, von denen eine nur die andere enthält, erzeugen nur Fragen.
jxh
1

Schauen Sie sich eine Header-Datei an und Sie werden ungefähr Folgendes sehen:

Diese Definitionen sind nicht nur zulässig, sondern auch von entscheidender Bedeutung, da jedes Mal, wenn auf die Header-Datei in Dateien verwiesen wird, diese separat aufgenommen wird. Dies bedeutet, dass Sie ohne die Definition alles zwischen den Wachen mehrmals neu definieren. Der beste Fall lässt sich nicht kompilieren, und im schlimmsten Fall kratzen Sie sich später am Kopf, warum Ihr Code nicht so funktioniert, wie Sie es möchten.

Der Compiler verwendet auch define, wie hier gezeigt, mit gcc , mit dem Sie beispielsweise die Version des Compilers testen können, die sehr nützlich ist. Ich arbeite derzeit an einem Projekt, das mit avr-gcc kompiliert werden muss, aber wir haben eine Testumgebung, in der wir auch unseren Code ausführen. Um zu verhindern, dass die avr-spezifischen Dateien und Register unseren Testcode nicht ausführen, gehen wir wie folgt vor:

Wenn dies im Produktionscode verwendet wird, kann der ergänzende Testcode ohne Verwendung von avr-gcc kompiliert werden, und der obige Code wird nur mit avr-gcc kompiliert.

Dom
quelle
1
In Organisationen, die die Verwendung des Prozessors verbieten, zählen Wachen nicht zu diesem Verbot. (In der Tat ist die Verwendung eines Include Guard in solchen Organisationen vorgeschrieben.)
David Hammen
1

Wenn Sie gerade erwähnt hätten #define, hätte ich gedacht, dass er vielleicht auf die Verwendung für Aufzählungen anspielt, die besser geeignet sind enum, um dumme Fehler wie das zweimalige Zuweisen desselben numerischen Werts zu vermeiden.

Beachten Sie, dass es selbst in dieser Situation manchmal besser ist, #defines als Aufzählungen zu verwenden, beispielsweise wenn Sie sich auf numerische Werte verlassen, die mit anderen Systemen ausgetauscht werden, und die tatsächlichen Werte auch dann gleich bleiben müssen, wenn Sie Konstanten hinzufügen / löschen (aus Kompatibilitätsgründen).

Jedoch , dass das Hinzufügen #if, #ifdefusw. sollten ebenfalls nicht verwendet werden , ist einfach seltsam. Natürlich sollten sie wahrscheinlich nicht missbraucht werden, aber im wirklichen Leben gibt es Dutzende Gründe, sie zu benutzen.

Was er möglicherweise gemeint hat, könnte sein, dass Sie (wo zutreffend) das Verhalten in der Quelle nicht fest codieren sollten (was eine Neukompilierung erfordern würde, um ein anderes Verhalten zu erhalten), sondern stattdessen eine Form der Laufzeitkonfiguration verwenden sollten.

Das ist die einzige Interpretation, die mir in den Sinn kommen würde.

jcaron
quelle