Gibt es eine Möglichkeit, a sizeof
in einem Präprozessor-Makro zu verwenden?
Zum Beispiel gab es im Laufe der Jahre eine Menge Situationen, in denen ich etwas tun wollte wie:
#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif
Das genaue, was ich hier überprüfe, ist vollständig erfunden - der Punkt ist, dass ich häufig diese Arten von Überprüfungen zur Kompilierungszeit (Größe oder Ausrichtung) einsetze, um zu verhindern, dass jemand eine Datenstruktur ändert, die falsch ausgerichtet oder neu ausgerichtet werden könnte Größe Dinge, die sie brechen würden.
Unnötig zu sagen - ich scheine nicht in der Lage zu sein, a sizeof
in der oben beschriebenen Weise zu verwenden.
Antworten:
Es gibt verschiedene Möglichkeiten, dies zu tun. Das Folgen von Snippets erzeugt keinen Code, wenn er
sizeof(someThing)
gleich istPAGE_SIZE
. Andernfalls wird ein Fehler beim Kompilieren erzeugt.1. C11 Weg
Ab C11 können Sie verwenden
static_assert
(erfordert#include <assert.h>
).Verwendung:
2. Benutzerdefiniertes Makro
Wenn Sie nur einen Fehler beim Kompilieren erhalten möchten, wenn dies
sizeof(something)
nicht Ihren Erwartungen entspricht, können Sie das folgende Makro verwenden:Verwendung:
Dieser Artikel erklärt ausführlich, warum es funktioniert.
3. MS-spezifisch
Im Microsoft C ++ - Compiler können Sie das Makro C_ASSERT (erforderlich
#include <windows.h>
) verwenden, das einen ähnlichen Trick wie den in Abschnitt 2 beschriebenen verwendet.Verwendung:
quelle
gcc
(getestet in Version 4.8.4) (Linux). Bei den((void)sizeof(...
es Fehler mitexpected identifier or '(' before 'void'
undexpected ')' before 'sizeof'
. Aber im Prinzipsize_t x = (sizeof(...
funktioniert es stattdessen wie beabsichtigt. Sie müssen das Ergebnis irgendwie "verwenden". Damit dies entweder innerhalb einer Funktion oder im globalen Bereich mehrmals aufgerufen werdenextern char _BUILD_BUG_ON_ [ (sizeof(...) ];
kann, kann so etwas wiederholt verwendet werden (keine Nebenwirkungen, eigentlich_BUILD_BUG_ON_
nirgendwo referenzieren ).Nein. Die bedingten Anweisungen enthalten nur eingeschränkte bedingte Ausdrücke.
sizeof
ist eines der Dinge, die nicht erlaubt sind.Vorverarbeitungsanweisungen werden ausgewertet, bevor die Quelle analysiert wird (zumindest konzeptionell), sodass noch keine Typen oder Variablen vorhanden sind, um ihre Größe zu ermitteln.
Es gibt jedoch Techniken, um Zusicherungen zur Kompilierungszeit in C abzurufen (siehe beispielsweise diese Seite ).
quelle
Ich weiß, dass es eine späte Antwort ist, aber um Mikes Version zu erweitern, hier ist eine Version, die wir verwenden und die keinen Speicher zuweist. Ich habe mir den Originalgrößencheck nicht ausgedacht, ich habe ihn vor Jahren im Internet gefunden und kann den Autor leider nicht referenzieren. Die anderen beiden sind nur Erweiterungen derselben Idee.
Da es sich um Typedefs handelt, wird nichts zugewiesen. Mit der __LINE__ im Namen ist es immer ein anderer Name, sodass er bei Bedarf kopiert und eingefügt werden kann. Dies funktioniert in MS Visual Studio C-Compilern und GCC Arm-Compilern. In CodeWarrior funktioniert es nicht. CW beschwert sich über eine Neudefinition und verwendet das Präprozessorkonstrukt __LINE__ nicht.
quelle
#define STATIC_ASSERT(condition) typedef char p__LINE__[ (condition) ? 1 : -1];
Ich weiß, dass dieser Thread wirklich alt ist, aber ...
Meine Lösung:
Solange dieser Ausdruck gleich Null ist, wird er gut kompiliert. Alles andere und es explodiert genau dort. Da die Variable extern ist, nimmt sie keinen Platz ein, und solange niemand darauf verweist (was sie nicht tun), verursacht sie keinen Linkfehler.
Nicht so flexibel wie das Assert-Makro, aber ich konnte das in meiner Version von GCC nicht kompilieren, und das wird ... und ich denke, es wird fast überall kompiliert.
quelle
Die vorhandenen Antworten zeigen nur, wie der Effekt von "Zusicherungen zur Kompilierungszeit" basierend auf der Größe eines Typs erzielt werden kann. Dies mag in diesem speziellen Fall den Anforderungen des OP entsprechen, aber es gibt andere Fälle, in denen Sie wirklich einen Präprozessor benötigen, der von der Größe eines Typs abhängig ist. So geht's:
Schreiben Sie sich ein kleines C-Programm wie:
Kompiliere das. Schreiben Sie ein Skript in Ihrer bevorzugten Skriptsprache, das das obige C-Programm ausführt und dessen Ausgabe erfasst. Verwenden Sie diese Ausgabe, um eine C-Header-Datei zu generieren. Wenn Sie beispielsweise Ruby verwenden, sieht es möglicherweise so aus:
Fügen Sie dann Ihrem Makefile oder einem anderen Build-Skript eine Regel hinzu, mit der das oben zu erstellende Skript ausgeführt wird
sizes.h
.Fügen
sizes.h
Sie ein, wo immer Sie Präprozessor-Bedingungen verwenden müssen, die auf Größen basieren.Getan!
(Haben Sie jemals geschrieben
./configure && make
, um ein Programm zu erstellen? Wasconfigure
Skripte tun, ist im Grunde genau wie oben ...)quelle
Was ist mit dem nächsten Makro:
Zum Beispiel sagt MSVC im Kommentar etwas wie:
quelle
#if
Präprozessor-Direktive verwenden können.Nur als Referenz für diese Diskussion berichte ich, dass einige Compiler sizeof () ar Pre-Prozessor-Zeit erhalten.
Die Antwort von JamesMcNellis ist korrekt, aber einige Compiler gehen diese Einschränkung durch (dies verstößt wahrscheinlich gegen strenge Ansi c).
In diesem Fall verweise ich auf den IAR C-Compiler (wahrscheinlich der führende für professionelle Mikrocontroller / Embedded-Programmierung).
quelle
sizeof
Zeitpunkt der Vorverarbeitung nicht zulassen .sizeof
sollte nur als Kennung behandelt werden.#if (sizeof(int) == 8)
tatsächlich funktionierten (bei einigen Compilern)." Die Antwort: "Muss vor meiner Zeit gewesen sein.", War von Dennis Ritchie.#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x))
könnte funktionierenquelle
#define SIZEOF_TYPE(x) (((x*)0) + 1)
#if
Bedingung verwenden können. Es bietet keinen Vorteil gegenübersizeof(x)
.In C11 wird ein
_Static_assert
Schlüsselwort hinzugefügt. Es kann verwendet werden wie:quelle
In meinem portablen C ++ - Code ( http://www.starmessagesoftware.com/cpcclibrary/ ) wollte ich die Größe einiger meiner Strukturen oder Klassen sicher schützen.
Anstatt eine Möglichkeit für den Präprozessor zu finden, einen Fehler auszulösen (der nicht mit sizeof () funktioniert, wie hier angegeben), habe ich hier eine Lösung gefunden, die den Compiler veranlasst, einen Fehler auszulösen. http://www.barrgroup.com/Embedded-Systems/How-To/C-Fixed-Width-Integers-C99
Ich musste diesen Code anpassen, damit ein Fehler in meinem Compiler (xcode) ausgelöst wurde:
quelle
Nach dem Ausprobieren der genannten Makros scheint dieses Fragment das gewünschte Ergebnis zu liefern (
t.h
):Laufen
cc -E t.h
:Laufen
cc -o t.o t.h
:42 ist doch nicht die Antwort auf alles ...
quelle
Der
sizeof
Operator ist für den Präprozessor nicht verfügbar, aber Sie könnensizeof
zum Compiler übertragen und die Bedingung zur Laufzeit überprüfen:quelle
compiler_size
? Was versucht Ihr Beispiel zu zeigen?