Ich habe kürzlich diesen Code ausprobiert und war ein wenig verwirrt. Siehe die folgenden Deklarationen:
%Vor% Sie alle belegen Speicher von 4 Bytes (auf 32 Bit GCC). Aber wenn ich versuche, ihre Größen zu drucken (mit printf
-Funktion), funktionieren sie nicht und geben Fehler.
Mein Zweifel ist auto, static, register
Schlüsselwörter auch Speicher von 4 Bytes (auf 32-Bit-Arch) zuzuteilen.
Aber warum geben diese Fehler anders als const
und volatile
?
In C vor dem Standard von 1999 würde ein unspezifizierter Typ in vielen Kontexten standardmäßig auf int
gesetzt.
C99 hat diese Regel fallen gelassen, und das Weglassen des Typs ist nun illegal (streng genommen handelt es sich um eine Constraint-Verletzung , die eine Diagnose erfordert - was eine nicht-fatale Warnung sein könnte). In jedem Fall war es immer eine schlechte Idee, den Typ int
wegzulassen. (Es geht zurück auf Cs Vorgängersprachen BCPL und B, die weitgehend typlos waren.)
Diese Deklarationen sind alle in C90 erlaubt (und alle Variablen sind vom Typ int
), aber sie sind in C99 ungültig.
Zu meiner Überraschung sind diese in C90 tatsächlich legal (aber nicht in C99). const
oder volatile
selbst ist ein Typname, der const int
bzw. volatile int
entspricht. Syntaktisch sind const
und volatile
type qualifiers .
Der Unterschied ist, dass dies:
%Vor% definiert x
als Objekt vom Typ const int
, während dies:
definiert x
als statisches Objekt vom Typ int
( static
ist nicht Teil des Typs).
Das sind Syntaxfehler, weil auto
, static
und register
keine Typnamen sind. Diese Schlüsselwörter sind Speicherklassenspezifizierer .
Dies erklärt, warum die ersten zwei sizeof
-Ausdrücke zu funktionieren scheinen und die anderen nicht. Aber das ist nicht besonders nützlich, denn wenn Sie den Typ int
angeben (was Sie immer tun sollten), spielt es keine Rolle, dass sizeof(const)
gültig ist (in C90, nicht in C99).
Im Endeffekt sollten Sie den Typ immer in einer Deklaration angeben. Und obwohl du sizeof (const int)
legal schreiben kannst, ist es garantiert dasselbe wie sizeof (int)
, also ist es nicht sehr sinnvoll, const
in diesem Kontext zu verwenden.
Vor C99 würde, wenn Sie keinen -Typ angegeben haben, int impliziert, was in Ihrem Code passiert. In der Praxis sieht es sogar im Modus C99 aus, dass gcc
und clang
nur Warnungen ausgeben. Dies ist ein Fall, in dem Compiler-Warnungen Ihr Freund sind. Ich habe das in clang -Wall
versucht:
und es warnt mich:
%Vor%Alle Erklärungen hier:
%Vor%hat auch einen implizierten int-Typ .
Wir können sehen, dass C99 die implizite int Annahme entfernt hat:
Eine Deklaration, für die kein Typspezifizierer vorhanden ist, wird nicht mehr implizit angenommen. Das C-Normenkomitee entschied, dass es für Compiler von größerem Wert wäre, eine versehentliche Auslassung des Typspezifizierers zu diagnostizieren, als stillgelegten Code, der auf implizitem int angewiesen war, still zu verarbeiten. In der Praxis zeigen Compiler wahrscheinlich eine Warnung an, nehmen dann int an und setzen die Übersetzung des Programms fort.
Wenn wir uns den Entwurf des C99-Standards ansehen Weiterleiten Abschnitt Absatz 5 enthält Folgendes:
[...] Wesentliche Änderungen gegenüber der vorherigen Ausgabe:
und hat das folgende Aufzählungszeichen:
- entferne implizites int
Aktualisieren
Warum also sizeof
nicht Speicherklassenbezeichner wie statisch und automatisch , aber mit Typqualifikatoren > em> like const und volatile , scheint das Verhalten mit der Funktionsweise der Deklarationen nicht konsistent zu sein und sollte die implizite int -Amplikation noch funktionieren?
Nun, wenn wir uns die Grammatik für sizeof
im Standard-Entwurf Abschnitt 6.5.3
anschauen, ist es wie folgt:
Also weder ein Typqualifikator noch ein Speicherklassenbezeichner ist ein Ausdruck , aber ein Typqualifikator ist a typname Wenn wir Abschnitt 6.7.6
betrachten, lautet die Grammatik für typname wie folgt:
und 6.7.2.1
geben uns die Grammatik für Spezifizierer-Qualifikationsmerkmal-Liste , die wie folgt lautet:
So können wir sehen, dass sizeof
Speicherklassenbezeichner nicht akzeptiert, selbst wenn der Typ explizit auf int festgelegt ist auch das Folgende ist ein Fehler:
und clang
sagen uns:
und wir können weiterhin sehen, dass Typnamen nicht mit sizeof
ohne ()
:
erzeugt einen Fehler:
%Vor% aber unäre Ausdrücke funktionieren mit ()
, wie ich zuvor hier erklärt habe.
Die Schlüsselwörter auto
, static
, register
identifizieren keinen Typ, aber ändert die Art, wie eine Variable dieses Typs gespeichert ist oder auf die zugegriffen wird.
Also:
%Vor%ergibt keinen Sinn, weil Sie nicht die Größe eines beliebigen Typs anfordern. Stattdessen:
%Vor% Diese identifizieren Typen: volatile int
und const int
. Sie können also sizeof
für sie verwenden.
Beachten Sie, dass der Compiler bei der Deklaration Ihrer Variablen int
als zugrunde liegenden Typ annimmt. Die meisten Compiler (GCC, Clang) geben Warnungen aus, wenn Sie sich auf dieses Verhalten verlassen.
extern
, static
, auto
, register
heißen Speicherklassenspezifizierer , während const
, restrict
, volatile
heißen Typ-Qualifier .
Bei Typqualifikatoren wird int
implizit in C89 angegeben, wenn sie ohne Typspezifizierer verwendet wird.
C89 §3.5.2 Typbezeichner
int
,signed
,signed int
oder keine Typbezeichner
Diese Typen sind identisch. Während keine Typbezeichner in C99 im selben Abschnitt entfernt wurde:
C99 §6.7.2 Typbezeichner
int
,signed
odersigned int
Ihre Deklarationen sind alle ungültig, daher sind die Ergebnisse weitgehend irrelevant.
Die Größe einer Variablen / eines Objekts hängt von seinem Datentyp ab, z. B. int
oder float
. Die Schlüsselwörter, die Sie ausprobiert haben, ändern die Art, wie der Compiler die Variable / das Objekt behandelt, aber sie ändern oder diktieren ihren Typ nicht (daher haben sie keinen Einfluss auf ihre Größe).
Für die Deklarationen const
und volatile
hat der Compiler wahrscheinlich int
eingegeben (dies ist aber kein Verhalten, auf das Sie sich verlassen sollten).
Tags und Links c gcc declaration sizeof