Warum ist sizeof int falsch, während sizeof (int) richtig ist?

96

Wir wissen, dass dies sizeofein Operator ist, der zum Berechnen der Größe eines Datentyps und Ausdrucks verwendet wird. Wenn der Operand ein Ausdruck ist, können die Klammern weggelassen werden.

int main()
{
        int a;

        sizeof int;
        sizeof( int );
        sizeof a;
        sizeof( a );

        return 0;
}

Die erste Verwendung von sizeofist falsch, während andere richtig sind.

Wenn es mit gcc kompiliert wird, wird die folgende Fehlermeldung ausgegeben:

main.c:5:9: error: expected expression before int

Meine Frage ist, warum der C-Standard diese Art von Betrieb nicht zulässt. Wird sizeof intes zu Mehrdeutigkeiten kommen?

Yishu Fang
quelle
5
Das Lustige ist, dass nicht alle Ausdrücke ohne Klammern akzeptiert werden: try sizeof (int)a.
Fred Foo
2
@MikkelK.: OP fragt nach den Gründen für die üblichen Zitate. Er kennt bereits die Zitate, die in der markierten Antwort erwähnt werden.
Alok Save
2
@ Lundin: sizeof +(int)ahat den Vorteil gegenüber dem *&tatsächlichen Kompilieren ;-)
Steve Jessop
2
@SteveJessop Ah richtig, es ist kein Wert. Obwohl es in Embarcadero C ++ kompiliert wurde, seltsamerweise. Wie auch immer, ich glaube, wir haben gerade eine Verwendung für den unären + Operator gefunden! Das muss das erste Mal in der Geschichte der C-Programmierung sein :)
Lundin
2
@Lundin: Du musst immer noch vorsichtig mit Unary sein +. Zum Beispiel ist es sizeof +(char)a == sizeof(int)aufgrund der Ganzzahl-Heraufstufung wahrscheinlich weniger fehleranfällig, nur in Klammern zu setzen, wenn Sie sich überhaupt Gedanken über den Ausdruck machen, dessen Größe Sie verwenden möchten. Ich bin mir also nicht sicher, ob ich es "eine Verwendung" nennen würde, obwohl ich
Steve Jessop

Antworten:

101

Folgendes könnte mehrdeutig sein:

sizeof int * + 1

Ist das (sizeof (int*)) + 1oder (sizeof(int)) * (+1)?

Natürlich hätte die C-Sprache eine Regel einführen können, um die Mehrdeutigkeit aufzulösen, aber ich kann mir vorstellen, warum es nicht störte. Bei der aktuellen Sprache erscheint ein Typspezifizierer in einem Ausdruck niemals "nackt", sodass keine Regeln erforderlich sind, um zu entscheiden, ob diese Sekunde *Teil des Typs oder eines arithmetischen Operators ist.

Die vorhandene Grammatik löst bereits die potenzielle Mehrdeutigkeit von sizeof (int *) + 1. Es ist (sizeof(int*))+1, nicht sizeof((int*)(+1)) .

C ++ hat ein ähnliches Problem, das mit der Cast-Syntax im Funktionsstil behoben werden muss. Sie können schreiben int(0)und Sie können schreiben typedef int *intptr; intptr(0);, aber Sie können nicht schreiben int*(0). In diesem Fall besteht die Auflösung darin, dass der "nackte" Typ ein einfacher Typname sein muss. Es kann sich nicht nur um eine alte Typ-ID handeln, die Leerzeichen oder nachfolgende Interpunktion enthält. Vielleicht sizeofhätte man mit der gleichen Einschränkung definieren können, ich bin mir nicht sicher.

Steve Jessop
quelle
1
C ++ hat, new int*(X)was mehrdeutig wäre, wenn C ++ nicht angeben würde, dass der neue Operator die längste Zeichenfolge verwendet, die möglicherweise ein Typ sein könnte. In C ++ hätten sie das gleiche mit sizeof machen können, denke ich. Aber in C ++ kann man sagen, sizeof int()was dann mehrdeutig gewesen wäre (Typ oder Wert initialisiert int?).
Johannes Schaub - litb
@ JohannesSchaub-litb: Mmmm, dann könnte C ++ vielleicht sagen, dass der Typ bevorzugt wird, wenn es möglich ist, einen zu analysieren, andernfalls ist es ein Ausdruck. Die Mehrdeutigkeit wäre gelöst, aber sizeof int()schlecht geformt ("nein operator()für size_t"), was ich erwarte, wäre unerwünscht!
Steve Jessop
32

Ab C99 Standard

6.5.3.4.2
Der sizeofOperator gibt die Größe (in Bytes) seines Operanden an, der ein Ausdruck oder der Name eines Typs in Klammern sein kann.

In Ihrem Fall intist weder Ausdruck noch Name in Klammern.

Jainendra
quelle
10
Ich verstehe nicht, warum dies 7 positive Stimmen bekommt. Wie bei den drei gelöschten Antworten wird die Regel nur wiederholt, anstatt zu erklären, warum die Regel vorhanden ist.
Fred Foo
7
@larsmans, ja, ich stimme dir zu. Es wiederholt zwar weiterhin die Regel, gibt aber zumindest eine autorisierende Lektüre.
Yishu Fang
3
@larsmans Wenn wir versuchen, jede in C99 getroffene Entscheidung zu rechtfertigen, sind wir das ganze Jahr hier. Das Zitieren des Standards ist eine gute Möglichkeit, diese Diskussion abzuschließen.
Perry
1
@Perry: Wenn Ihnen diese Art von Frage nicht gefällt, können Sie abstimmen, um die Frage als argumentativ zu schließen.
Fred Foo
4
Als Nicht-Praktiker von C ++ verstehe selbst ich diese Antwort und bin mir nicht sicher, wo das Problem liegt, wenn Sie Englisch lesen und verstehen können.
Kev
6

Es gibt zwei Möglichkeiten, den Operator sizeof in C zu verwenden. Die Syntax lautet wie folgt:

C11 6.5.3 Unary operators
...
sizeof unary-expression
sizeof ( type-name )

Wenn Sie einen Typ als Operanden verwenden, müssen Sie die Klammer gemäß der Syntaxdefinition der Sprache haben. Wenn Sie sizeof für einen Ausdruck verwenden, benötigen Sie die Klammer nicht.

Der C-Standard gibt ein Beispiel dafür, wo Sie ihn möglicherweise für einen Ausdruck verwenden möchten:

sizeof array / sizeof array[0]

Aus Gründen der Konsistenz und um Fehler im Zusammenhang mit der Priorität des Bedieners zu vermeiden, würde ich persönlich empfehlen, immer () zu verwenden, unabhängig von der Situation.

Lundin
quelle
@ JohannesSchaub-litb Ich stimme zu, dass es keine Begründung dafür gibt, wie das C-Standard-Komitee argumentiert hat, als es den C90-Standard spezifizierte. Sie müssten sie fragen ... Es wird ohne Begründung geantwortet, C lässt dies jedoch nicht zu, da die Syntax der in 6.5.3 angegebenen entspricht. Das OP schien sich auch des Unterschieds zwischen sizeof expressionund nicht bewusst zu sein sizeof(type), der in dieser Antwort erläutert wird.
Lundin
(Für die Aufzeichnung habe ich gerade sowohl die C90- als auch die C11-Rationales gelesen und keine liefert eine Erklärung.)
Lundin
Ich vermute, es gibt keine notwendigen Gründe dafür, es ist nur die Art und Weise, wie sich die ursprünglichen C-Designer dazu entschlossen haben. Vielleicht hat es dem frühen Parser die Sache leichter gemacht. Ich wollte eine Antwort auf die Tatsache posten, dass Typedefs und Variablen denselben Namespace haben, aber das schließt nicht aus, die erste Syntax zuzulassen. Es müssen nur die Parsing-Regeln verwendet werden, um zu sagen, dass die Variable bevorzugt wird, wenn keine Parens vorhanden sind, der Typ bevorzugt wird, wenn vorhanden, und jede Form kann verwendet werden, wenn der Name eindeutig ist. Da es nicht notwendig ist, es zu ändern, ließen die Normungsausschüsse es in Ruhe.
Barmar