Gibt es in C/C++ eine Direktive ähnlich #ifndef für Typedefs?

Lesezeit: 7 Minuten

Benutzeravatar von Zach Rattner
Zach Rattner

Wenn ich einen Wert nur definieren möchte, wenn er nicht definiert ist, gehe ich so vor:

#ifndef THING
#define THING OTHER_THING
#endif

Was wäre wenn THING ist ein typedef‘d Bezeichner und nicht definiert? Ich möchte so etwas tun:

#ifntypedef thing_type
typedef uint32_t thing_type
#endif

Das Problem trat auf, weil ich überprüfen wollte, ob eine externe Bibliothek die bereits definiert hat boolean Typ, aber ich wäre offen für eine allgemeinere Lösung.

  • @ZachRattner: Nur zu Ihrer Information, wenn Ihr Compiler MSVC, __if_not_exists ist in C++ verfügbar. Zum Beispiel ein Code wie __if_not_exists( thing_type ) { typedef uint32_t thing_type; } ist möglich.

    – Ise Glyzinie

    21. Juli 2011 um 8:32 Uhr

  • In C11 und C++ dürfen Sie eine Typedef auf dasselbe umschreiben

    – MM

    16. Februar 2017 um 0:37 Uhr

So etwas gibt es in der Sprache nicht und wird auch nicht benötigt. Innerhalb eines einzelnen Projekts sollten Sie niemals denselben Typedef-Alias ​​haben, der sich auf verschiedene Typen bezieht, da dies eine Verletzung des ODR darstellt, und wenn Sie denselben Alias ​​für denselben Typ erstellen, tun Sie es einfach. Die Sprache ermöglicht es Ihnen, denselben Typedef so oft auszuführen, wie Sie möchten, und fängt normalerweise diesen bestimmten ODR (innerhalb derselben Übersetzungseinheit) ab:

typedef int myint;
typedef int myint;       // OK: myint is still an alias to int
//typedef double myint;  // Error: myint already defined as alias to int

Wenn Sie beabsichtigen, eine Funktion für verschiedene Typen zu implementieren, indem Sie eine Typedef verwenden, um zu bestimmen, welche verwendet werden soll, dann sollten Sie sich eher mit Vorlagen als mit Typedefs befassen.

  • NB: FYI für C ist es nicht gültig, eine Typedef mehr als einmal zu deklarieren, selbst wenn sie beide den gleichen Typ haben. Siehe stackoverflow.com/a/8367810/816536

    – Greg A. Woods

    18. Oktober 2015 um 22:49 Uhr

  • Nicht wahr. Beim Schreiben von Bibliotheken kann dies leicht vorkommen. Was verwenden Sie in einer Header-Datei, wenn eine Funktion einen booleschen Wert zurückgeben soll? Wenn Ihre Bibliothek in einem X-Projekt verwendet wird, dann definiert X bereits BOOL. Wenn Sie Ihre Bibliothek in einem anderen Projekt verwenden, gibt es möglicherweise eine andere und völlig inkompatible Definition von Bool.

    – swestrup

    10. Juni 2016 um 16:32 Uhr

  • @GregA.Woods C11 hat diese Funktion zu C hinzugefügt; Die Antwort, mit der Sie verknüpft sind, beantwortet nur C99

    – MM

    16. Februar 2017 um 0:39 Uhr

  • Diese Funktion wäre nützlich für ein Projekt, das mit C89- und C99-Compilern auf verschiedenen Plattformen ohne Codeänderungen funktionieren soll und einige der Typedefs in C99 hinzufügen möchte, z. B. uintmax_t. Eine Header-Datei könnte die Typedef emulieren, falls sie noch nicht verfügbar ist.

    – chw

    8. Dezember 2017 um 3:49 Uhr

Benutzeravatar von Alok Save
Alok Speichern

C++ bietet keinen Mechanismus für Code, um das Vorhandensein zu testen typedefdas Beste, was Sie haben können, ist so etwas:

#ifndef THING_TYPE_DEFINED
#define THING_TYPE_DEFINED
typedef uint32_t thing_type 
#endif

BEARBEITEN:
Wie @David in seinem Kommentar richtig ist, beantwortet dies die wie? Teil vermisst aber vor allem die warum? Es kann auf die obige Weise gemacht werden. Wenn Sie es überhaupt tun möchten, aber wichtig ist, müssen Sie es wahrscheinlich sowieso nicht tun. @Davids Antwort und Kommentar erklären die Details, und ich denke, das beantwortet die Frage richtig.

  • Das ist hässlich und nicht zu gebrauchen. Die wichtige Frage ist nicht, wie das geht, sondern warum würdest du es tun? Und die Antwort bist du sollte nicht. Eine Typedef kann innerhalb derselben Übersetzungseinheit so oft neu definiert werden, wie Sie möchten (vorausgesetzt, dass sie immer denselben Typ aliasiert), so dass dies kein Problem darstellt. Es zu definieren, um verschiedene Typen in verschiedenen Übersetzungseinheiten desselben Programms als Alias ​​zu definieren, ist eine Verletzung des ODR, also wollen Sie das auch nicht. Das Beste, was Sie bekommen können, ist nichts wenn der Alias ​​immer gleich ist, oder versteckt ein Fehler zur Kompilierungszeit, je nachdem, was zuvor enthalten war.

    – David Rodríguez – Dribeas

    21. Juli 2011 um 8:10 Uhr


  • @David Rodríguez – dribeas: Ich stimme zu, ich glaube, ich habe einen verpasst why? und sprang einfach auf die how? ein Teil davon. Ich werde eine Anmerkung dazu hinzufügen.

    – Alok Speichern

    21. Juli 2011 um 8:23 Uhr

Benutzeravatar von iammilind
iammilind

Nein, es gibt keine solche Einrichtung in C++ in der Vorverarbeitungsphase. Höchstens tun können ist

#ifndef thing_type
#define thing_type uint32_t 
#endif

Obwohl dies keine gute Codierungspraxis ist und ich es nicht vorschlage.

  • Ich habe nicht abgelehnt, aber ich bevorzuge es, wenn Leute mir sagen, was an einer Antwort falsch ist, anstatt nur eine Ablehnung. Das Problem bei diesem Ansatz ist das typedef erstellt einen echten Alias ​​für den Typ, während ein Makro ist nur Textersetzung. Im Beispiel spielt es keine Rolle, sondern die Semantik von void foo( const X x ) sind sehr unterschiedlich, je nachdem, ob X ist ein typedef oder das obige Makro: typedef int* X wird die Funktion machen void foo( int * const )während #define X int* wird es schaffen void foo( int const * ) (verflixt const ganz links!)

    – David Rodríguez – Dribeas

    21. Juli 2011 um 8:05 Uhr

  • definiert != typedefs. Definiert eigentlich < typedefs. Schlechte Programmierpraxis.

    – DevSolar

    21. Juli 2011 um 8:05 Uhr

  • @DevSolar, ich unterstütze diese Technik nicht; das ist einer der Wege.

    – iammilind

    21. Juli 2011 um 9:24 Uhr

Benutzeravatar von Mike Seymour
Mike Seymour

Präprozessordirektiven (wie #define) sind grobe Textersetzungswerkzeuge, die nichts über die Programmiersprache wissen und daher nicht auf Definitionen auf Sprachebene reagieren können.

Es gibt zwei Ansätze, um sicherzustellen, dass ein Typ nur einmal definiert wird:

  • Strukturieren Sie den Code so, dass jede Definition ihren Platz hat und nicht mehrere Definitionen erforderlich sind
  • #define ein Präprozessor-Makro neben dem Typ und der Verwendung #ifndef um die Makrodefinition zu überprüfen, bevor der Typ definiert wird.

Die erste Option führt im Allgemeinen zu besser wartbarem Code. Der zweite könnte subtile Fehler verursachen, wenn Sie versehentlich mit unterschiedlichen Definitionen des Typs innerhalb eines Programms enden.

Wie andere bereits gesagt haben, gibt es so etwas nicht, aber wenn Sie versuchen, einen Alias ​​für einen anderen Typ zu erstellen, erhalten Sie einen Kompilierungsfehler:

typedef int myInt;
typedef int myInt;    // ok, same alias
typedef float myInt;  // error

Allerdings gibt es eine Sache namens ctag um herauszufinden, wo eine Typedef definiert ist.

  • Danke für die Erwähnung von ctags. Das war mir neu.

    – Josh Sanford

    13. April 2017 um 16:07 Uhr

Swift - Benutzeravatar von Friday Pie
Swift – Freitagskuchen

Das Problem ist eigentlich echtes PITA, denn einige APIs oder SDKs definieren häufig verwendete Dinge neu. Ich hatte das Problem, dass Header-Dateien für eine Kartenverarbeitungssoftware (GIS) TRUE- und FALSE-Schlüsselwörter (im Allgemeinen von Windows SDK verwendet) in Ganzzahlliterale anstelle von wahren und falschen Schlüsselwörtern umdefinierten (offensichtlich kann das ETWAS beschädigen). Und ja, der berühmte Witz „#define true false“ ist relevant.

define würde niemals eine in C\C++-Code deklarierte Typedef oder Konstante erkennen, da der Präprozessor den Code nicht analysiert, sondern nur nach #-Anweisungen sucht. Und es ändert den Code, bevor es an den Syntaxanalysator übergeben wird. SO, im Allgemeinen ist es nicht möglich.

https://msdn.microsoft.com/en-us/library/5xkf423c.aspx?f=255&MSPPError=-2147217396
Dieser ist bisher nicht portierbar, obwohl es bekannte Anfragen gab, ihn in GCC zu implementieren. Ich denke, es zählt auch als “Erweiterung” in MSVC. Es ist eine Compiler-Anweisung, keine Präprozessor-Anweisung, daher “fühlt” es keine definierten Makros, es würde nur Typedefs außerhalb des Funktionskörpers erkennen. “full type” bedeutet dort, dass es auf die volle Definition reagiert und Aussagen wie “class SomeClass;” ignoriert. Verwenden Sie es auf eigene Gefahr.

Bearbeiten: Anscheinend wird es jetzt auch auf MacOS unterstützt und vom Intel-Comiler mit -fms-dialect-Flag (AIX\Linux?)

  • Danke für die Erwähnung von ctags. Das war mir neu.

    – Josh Sanford

    13. April 2017 um 16:07 Uhr

Dies beantwortet die Frage möglicherweise nicht direkt, dient jedoch als mögliche Lösung für Ihr Problem.

Warum nicht so etwas ausprobieren?

#define DEFAULT_TYPE int // just for argument's sake
#ifndef MY_COOL_TYPE
     #define MY_COOL_TYPE DEFAULT_TYPE
#endif
typedef MY_COOL_TYPE My_Cool_Datatype_t;

Wenn Sie dann den Typ anpassen möchten, können Sie entweder MY_COOL_TYPE irgendwo darüber definieren (wie in einem “configure” -Header, der oben in diesem Header enthalten ist) oder ihn beim Kompilieren als Befehlszeilenargument übergeben (soweit I wissen, dass Sie dies mit GCC und LLVM tun können, vielleicht auch mit anderen).

1409930cookie-checkGibt es in C/C++ eine Direktive ähnlich #ifndef für Typedefs?

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

Privacy policy