Kompilierzeit sizeof bedingt

Lesezeit: 5 Minuten

Benutzer-Avatar
Alexej Romanow

Ich möchte ein Makro definieren, wenn eine Bedingung involviert ist sizeof wahr ist und nichts tut (aber dennoch kompiliert), wenn es falsch ist. Wenn der Präprozessor unterstützt sizeofdas sähe so aus:

#if (sizeof(void*) <= sizeof(unsigned int)) // what goes here?
#  define POINTER_FITS_INTO_UINT
#endif

Es gibt einige Seiten (zB http://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/), die erklären, wie man eine Kompilierzeit erstellt Behauptung an sizeof (und kann nicht kompilieren, wenn es fehlschlägt), aber ich sehe keine Möglichkeit, diesen Ansatz auf das zu erweitern, was ich will.

  • … Und was genau wollen Sie anders machen, je nachdem, ob Zeiger in uints passen? Was auch immer es ist, es ist normalerweise eine schlechte Idee….

    – Karl Knechtel

    7. Dezember 2010 um 8:01 Uhr

  • Übergeben Sie die Zeiger an einen anderen Prozess, der später in die Bibliothek zurückruft (und unsigned int können direkt übergeben werden, während 64-Bit-Typen selbst als Zeiger übergeben werden müssen).

    – Alexej Romanow

    7. Dezember 2010 um 8:22 Uhr

  • Nein, tun sie nicht. Sie können einen 64-Bit-Wert auf herkömmliche Weise übergeben – selbst wenn Sie für 32 Bit kompilieren (was Sie wahrscheinlich nicht sind, wenn Ihre Zeiger 64 Bit sind).

    – JeremyP

    7. Dezember 2010 um 10:05 Uhr

  • Ja, in diesem Fall tun sie das: siehe Tabelle in erlang.org/doc/man/erl_driver.html#driver_output_term

    – Alexej Romanow

    7. Dezember 2010 um 10:40 Uhr

  • Was ist falsch daran, immer zu verwenden intptr_t?

    – Christoph Creutzig

    8. Dezember 2010 um 12:26 Uhr

Du kannst es einfach nicht. sizeof ist ein Kompilierzeitoperator. #if und #define und Präprozessor bezogen. Da der Präprozessor VOR dem Compiler läuft, funktioniert dies einfach nicht. Möglicherweise finden Sie jedoch einen geheimen Compiler-Schalter, mit dem Sie ihn mehrfach übergeben können (dh vorverarbeiten, vorgeben, kompilieren, vorverarbeiten, kompilieren), aber fairerweise würde ich es aufgeben, zu versuchen, das zu tun, was Sie wollen. Es soll nicht funktionieren und tut es einfach nicht.

Am besten setzen Sie solche Definitionen als -D-Befehle, die an den Compiler übergeben werden. Sie können statisch behaupten, dass die ausgewählten korrekt sind. Auf diese Weise müssen Sie nur ein paar Definitionen extern für einen bestimmten Kompilierungsmodus (z. B. PowerPC-Release) und so weiter einrichten.

  • Das Beste Der Ansatz besteht darin, Ihr Build-System (Autotools usw.) zu verwenden, um Prüfungen durchzuführen und eine systemkonfigurierte Datei damit zu erstellen #define SIZEOF_POINTER 4 oder was auch immer, und das dann verwenden.

    – Chris Lutz

    7. Dezember 2010 um 7:58 Uhr

  • Es ist erwähnenswert, dass in C11 _Static_assert wird erreichen, was OP will.

    – Tschad

    18. August 2016 um 21:07 Uhr

Benutzer-Avatar
Jonathan Leffler

Die richtige Lösung für Ihr Problem ist die Verwendung der C99-Standardheader:

#include <stdint.h>
#include <inttypes.h>

Da braucht man nur eines von beiden #include <inttypes.h> enthält das Material von #include <stdint.h>; jedoch viel Material drin <inttypes.h> ist nur relevant für formatierte I/O mit scanf() und printf().

Angesichts der mutmaßlichen Bedingung:

#if (sizeof(void*) <= sizeof(unsigned int)) // what goes here?
#  define POINTER_FITS_INTO_UINT
#endif

Was Sie zu suchen scheinen, ist bekannt als:

uintptr_t

Das ist der vorzeichenlose Integer-Typ, der groß genug ist, um jeden Zeiger aufzunehmen (d. h. jeden Datenzeiger im C-Standard; POSIX erlegt eine zusätzliche Regel auf, dass er auch groß genug sein muss, um auch Funktionszeiger aufzunehmen). Der Typ uintptr_t ist darin definiert <stdint.h>.

Wenn Sie später solche Werte oder Rohzeiger drucken, können Sie die Informationen aus verwenden <inttypes.h>:

printf("Pointer = 0x%" PRIXPTR "\n", uintptr_value);
printf("Pointer = 0x%" PRIXPTR "\n", (uintptr_t)any_pointer);

Dies beschreibt, wie Assertionen zur Kompilierzeit in C vorgetäuscht werden. Die Kurzversion besteht darin, switch-Anweisungen zu verwenden:

#define COMPILE_TIME_ASSERT(pred)            \  
    switch(0){case 0:case pred:;}

Wenn pred zu 0 ausgewertet wird, wie es ein falscher boolescher Ausdruck in C tut, gibt der Compiler einen Fehler aus.

  • +1. Ich habe etwas Ähnliches verwendet, um ein Array mit der Größe 0 oder -1 zu deklarieren (-1 verursacht einen Kompilierungsfehler), aber ich denke, die Verwendung von switch ist ordentlicher.

    – qbert220

    19. Oktober 2012 um 9:02 Uhr

Unter der Annahme von C99 könnten Sie verwenden

#include <limits.h>
#include <stdint.h>

#if UINTPTR_MAX <= UINT_MAX
...

was impliziert sizeof (void *) <= sizeof (intptr_t) <= sizeof (int) auf jede vernünftige Implementierung der C-Sprache.

Benutzer-Avatar
stewori

Angesichts der Tatsache, dass die anderen Antworten bereits erklärt haben, warum sizeof kann nicht mit verwendet werden #if, lassen Sie mich eine einfache Lösung für Ihren Fall anbieten (überraschenderweise noch nicht erwähnt). Schauen Sie sich an

https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html#Common-Predefined-Macros.

Es erwähnt mehrere vordefinierte __SIZEOF_XYZ__ Makros, die tatsächlich in der Vorverarbeitungsphase verwendet werden können, dh auch in #if. Vorausgesetzt unsigned int und int gleich groß sind, kann Ihr Beispiel so aussehen:

#if __SIZEOF_POINTER__ == __SIZEOF_INT__
#define POINTER_FITS_INTO_UINT
#endif

Benutzer-Avatar
Roddy

Obwohl die Frage eher mit C als mit C++ gekennzeichnet ist, ist es möglicherweise hilfreich zu wissen, dass C++0x einen Mechanismus für statische Zusicherungen definiert, die vom Compiler und nicht vom Präprozessor überprüft werden.

Das Wikipedia-Beispiel ist besonders relevant:

static_assert (sizeof(int) <= sizeof(T), "T is not big enough!")

Benutzer-Avatar
Gemeinschaft

Bearbeiten

Egal, wie Steve Rowe betonte, diese Präprozessorwerte werden von eingestellt sizeof auch, so dass wir gerade den Kreis geschlossen haben.

Seit sizeof erst zur Kompilierzeit ausgewertet wird, müssen Sie sich auf andere Präprozessorwerte verlassen. So würde ich es machen:

#include <values.h>
#if PTRBITS <= INTBITS
#  define POINTER_FITS_INTO_UINT
#endif

  • Wie werden PTRBITS und INTBITS gesetzt?

    – Steve Rowe

    7. Dezember 2010 um 7:58 Uhr

  • Aus values.h : #define _TYPEBITS(type) (sizeof (type) * CHAR_BIT) #define INTBITS _TYPEBITS (int) #define PTRBITS _TYPEBITS (char *) Ich weiß nicht, wo CHAR_BIT gesetzt ist, aber INTBITS und PTRBITS sind immer noch sizeof Ausdrücke.

    – Oper

    7. Dezember 2010 um 8:08 Uhr


  • @Opera: Es bedeutet nur, dass INTBITS usw. nicht vom Präprozessor analysiert werden können. Die Makros können nicht in a verwendet werden #if oder ähnliche Aussage. Die Makros können im eigentlichen Code erscheinen, aber nicht in Präprozessordirektiven.

    – Jonathan Leffler

    7. Dezember 2010 um 8:14 Uhr


1255390cookie-checkKompilierzeit sizeof bedingt

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

Privacy policy