104

We know that sizeof is an operator used for calculating the size of any datatype and expression, and when the operand is an expression, the parentheses can be omitted.

int main()
{
        int a;

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

        return 0;
}

the first usage of sizeof is wrong, while others are right.

When it is compiled using gcc, the following error message will be given:

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

My question is why the C standard does not allow this kind of operation. Will sizeof int cause any ambiguity?

Yishu Fang
  • 9,448
  • 21
  • 65
  • 102
  • 7
    The funny thing is that not all expressions are accepted without parentheses: try `sizeof (int)a`. – Fred Foo Oct 29 '12 at 11:17
  • 2
    @MikkelK.: OP is asking reasoning behind the standardese quotes he already knows the quotes which are mentioned in marked answer. – Alok Save Oct 29 '12 at 11:28
  • 1
    @larsmans I guess that's because a parenthesis following the sizeof gets interpreted as part of the sizeof operator, rather than something belonging to the rest of the expression (which would have been the type cast operator). So if I understand this correctly, you could have written something obscure like `sizeof *&(int)a` and then it would have been fine, since we end up with an expression and not a type. – Lundin Oct 29 '12 at 14:39
  • 2
    @Lundin: `sizeof +(int)a` has the advantage over `*&` of actually compiling ;-) – Steve Jessop Oct 29 '12 at 14:41
  • 2
    @SteveJessop Ah right, it is not a lvalue. Though it did compile in Embarcadero C++, oddly enough. Anyway, I believe we just now found a use for the unary + operator! That must be the first time in the history of C programming :) – Lundin Oct 29 '12 at 14:46
  • 3
    @Lundin: You still have to be careful with unary `+`. For example, `sizeof +(char)a == sizeof(int)` due to integer promotion, it's probably less error-prone just to put in the parentheses if there's any worry at all about the expression you're trying to take the size of. So I'm not sure I'd go so far as to call it "a use", although I admit I did use it... – Steve Jessop Oct 29 '12 at 14:49
  • @SteveJessop Indeed. All of this is excellent material for the [IOCCC](http://www.ioccc.org/), but perhaps not for real life code :) – Lundin Oct 29 '12 at 14:53
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/18725/discussion-between-lundin-and-steve-jessop) – Lundin Oct 29 '12 at 15:08

3 Answers3

107

The following could be ambiguous:

sizeof int * + 1

Is that (sizeof (int*)) + 1, or (sizeof(int)) * (+1)?

Obviously the C language could have introduced a rule to resolve the ambiguity, but I can imagine why it didn't bother. With the language as it stands, a type specifier never appears "naked" in an expression, and so there is no need for rules to resolve whether that second * is part of the type or an arithmetic operator.

The existing grammar does already resolve the potential ambiguity of sizeof (int *) + 1. It is (sizeof(int*))+1, not sizeof((int*)(+1)).

C++ has a somewhat similar issue to resolve with function-style cast syntax. You can write int(0) and you can write typedef int *intptr; intptr(0);, but you can't write int*(0). In that case, the resolution is that the "naked" type must be a simple type name, it can't just be any old type id that might have spaces in it, or trailing punctuation. Maybe sizeof could have been defined with the same restriction, I'm not certain.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 1
    C++ has `new int*(X)` which would be ambiguous if C++ didnt specify that the new operator takes the longest string that could possibly be a type. So In C++ they could have made the same with sizeof, I guess. But in C++ you can say `sizeof int()` which then would have been ambiguous (type or value initialized int?). – Johannes Schaub - litb Oct 30 '12 at 10:06
  • @JohannesSchaub-litb: Mmm, so perhaps then C++ could say that the type is preferred if it's possible to parse one, otherwise it's an expression. The ambiguity would be resolved but `sizeof int()` would be ill-formed ("no `operator()` for `size_t`"), which I expect would be unwelcome! – Steve Jessop Oct 30 '12 at 12:12
31

From C99 Standard

6.5.3.4.2
The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type.

In your case int is neither expression nor parenthesized name.

Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166
Jainendra
  • 24,713
  • 30
  • 122
  • 169
  • 12
    I don't understand why this gets 7 upvotes. Like the three deleted answers, it just repeats the rule instead of explaining why the rule exists. – Fred Foo Oct 29 '12 at 14:08
  • 8
    @larsmans, yes, I agree with you. Although it continues to repeat the rule, but at least, it gives a piece of authorizing reading. – Yishu Fang Oct 29 '12 at 14:31
  • 3
    @larsmans If we start trying to justify every decision made in C99 we'll be here all year. Quoting the standard is as good a way as any to wrap up this discussion. – Perry Oct 30 '12 at 18:50
  • 1
    @Perry: if you don't like this kind of question, you can vote to close the question as argumentative. – Fred Foo Oct 30 '12 at 19:33
  • 4
    As a non-practitioner of C++, even I understand this answer, not sure what the problem is if you can read and comprehend english. – Kev Oct 30 '12 at 23:52
  • +1 What has puzzled me is that `int;` compiles; so I incorrectly though that it must also be an _expression_. After taking a look at your referred standard, it turns out that there are a few grammar rules (6.7): `declaration: declaration-specifiers init-declarator-list[opt] ;`, `declaration-specifiers: type-specifier declaration-specifiers[opt]`, and `type-specifier: int` that define `int;` as a _declaration_, not an _expression_ ([opt] means optional). Thanks for the quote and linked document. – Alberto Oct 31 '12 at 09:51
7

There are two ways to use the sizeof operator in C. The syntax is this:

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

Whenever you use a type as operand, you must have the parenthesis, by the syntax definition of the language. If you use sizeof on an expression, you don't need the parenthesis.

The C standard gives one such example of where you might want to use it on an expression:

sizeof array / sizeof array[0]

However, for the sake of consistency, and to avoid bugs related to operator precedence, I would personally advise to always use () no matter the situation.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • @JohannesSchaub-litb I agree that it doesn't provide any rationale for how the C standard committee reasoned when they specified the C90 standard. You'd have to ask them... It does answer without any rationale provided, however, C does not allow it since the syntax is as specified in 6.5.3. The OP also seemed unaware of the difference between `sizeof expression` and `sizeof(type)`, which is explained in this answer. – Lundin Oct 30 '12 at 10:51
  • (For the record, I did just read both the C90 and C11 rationales and neither provides any explanation.) – Lundin Oct 30 '12 at 10:54
  • 1
    I suspect there's no necessary rationale for it, it's just the way the original C designers decided to do it. Maybe it made things easier for the early parser. I was going to post an answer about the fact that typedefs and variables share the same namespace, but that doesn't preclude allowing the first syntax; it just needs the parsing rules to say that it prefers the variable when there's no parens, prefers the type when there are, and either form can be used when the name is unambiguous. Since there's no need to change it, the standards committees left it alone. – Barmar Oct 30 '12 at 19:32