Verwirrende Ergebnisse vom Operator 'sizeof'

7

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.

%Vor%

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 ?

    
SGG 31.10.2013, 15:00
quelle

5 Antworten

17

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.)

%Vor%

Diese Deklarationen sind alle in C90 erlaubt (und alle Variablen sind vom Typ int ), aber sie sind in C99 ungültig.

%Vor%

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 .

%Vor%

Der Unterschied ist, dass dies:

%Vor%

definiert x als Objekt vom Typ const int , während dies:

%Vor%

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.

    
Keith Thompson 31.10.2013, 15:15
quelle
10

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:

%Vor%

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:

%Vor%

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:

%Vor%

und 6.7.2.1 geben uns die Grammatik für Spezifizierer-Qualifikationsmerkmal-Liste , die wie folgt lautet:

%Vor%

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:

%Vor%

und clang sagen uns:

%Vor%

und wir können weiterhin sehen, dass Typnamen nicht mit sizeof ohne () :

funktionieren %Vor%

erzeugt einen Fehler:

%Vor%

aber unäre Ausdrücke funktionieren mit () , wie ich zuvor hier erklärt habe.

    
Shafik Yaghmour 31.10.2013 15:03
quelle
1

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.

    
peppe 31.10.2013 15:10
quelle
1

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 oder signed int

    
Yu Hao 31.10.2013 15:15
quelle
0

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).

    
Peter Bloomfield 31.10.2013 15:17
quelle

Tags und Links