In C.1.3 of the C++ IS (2003. It's in the C++11 IS, too), the standard points out a difference between ISO C and C++; namely, for
char arr[100];
sizeof(0, arr)
returns sizeof(char*)
in C, but 100
in C++.
I can find no documentation for sizeof
taking two arguments. The obvious fallback is the comma operator, but I don't think so: sizeof(arr)
in C is 100
; sizeof(0, arr)
is sizeof(char*)
. Both sizeof(0, arr)
and sizeof(arr)
are 100
in C++.
I may be missing the whole point of the IS in this context. Can anyone help? This is similar to a question discussed back in '09, but no one referred to the IS, and I don't think the correct answer was given.
Edit: Actually, the IS is talking about the comma operator. So, for some reason (0, arr)
returns a char*
in C, but a char[100]
in C++. Why?
In C then the array is decaying to a pointer, because of the different specification of the comma operator with relation to rvalues and lvalues (not the only place such a difference can be found). In C++ then the array stays an array, yielding the correct result.
In C, comma operator doesn't produce an lvalue, consequently the array arr
which is an lvalue decays into a pointer type which is a rvalue (in this case). So sizeof(0,arr)
becomes equivalent to sizeof(char*)
, due to lvalue-to-rvalue conversion.
But in C++, comma operator produces an lvalue. There is no lvalue-to-rvalue conversion. So sizeof(0,arr)
remains same, which is equivalent to sizeof(char[100])
.
By the way, sizeof
is not a function, it's an operator. So the following is completely valid C++ (and C, if you imagine printf
instead of cout
):
int a[100], b[200], c[300], d[400];
cout << sizeof(a,b,c,d) << endl;
Demo : http://www.ideone.com/CtEhn
You might think that I've passed 4 operands to sizeof
but that is wrong. sizeof
operates on the result of the comma operators. And its because of the many comma operators you see many operands.
4 operands with 3 comma operators; just like in 1+2+3+4
, there're 3 operators, 4 operands.
The above is equivalent to the following (valid in C++0x):
auto & result = (a,b,c,d); //first all comma operators operate on the operands.
cout << sizeof (result) << endl; //sizeof operates on the result
Demo : http://www.ideone.com/07VNf
So it's the comma operator which makes you feel that there are many arguments. Here comma is an operator, but in function call, comma is NOT an operator, its simply argument separator.
function(a,b,c,d); //here comma acts a separator, not operator.
So sizeof(a,b,c,d)
operates on the type of the result of ,
operators, exactly in the same way, sizeof(1+2+3+4)
operates on the type of the result of +
operators.
Also note that you cannot write sizeof(int, char, short)
, precisely because comma operator cannot operate on types. It operates on value only. I think, sizeof
is the only operator in C and C++, which can operate on types as well. In C++, there is one more operator which can operates on types. Its name is typeid
.
It is a comma operator. And the difference you are talking about has absolutely nothing to do with sizeof
. The difference is really in lvalue-to-rvalue, array-to-pointer and similar decay behaviors between C and C++ languages.
C language is rather trigger-happy in this regard: arrays decay to pointers practically immediately (with the exception of very few specific contexts), which is why the result of 0, arr
expression has char *
type. It is equivalent to 0, (char *) arr
.
In C++ language arrays preserve they "arrayness" much longer. When used in the context of ,
operator arrays don't decay to pointers (and lvalues do not decay to rvalues), which is why in C++ the type of 0, arr
expression is still char[100]
.
This is what explains the difference in sizeof
behavior in that example. ?:
operator is another example of an operator that demonstrates the similar difference in decay behavior, i.e. sizeof(0 ? arr : arr)
will give you different results in C and C++. Basically, it all stems from the fact that C operators don't usually preserve the lvalueness of their operands. A lot of operators can be used to demonstrate this behavior.
This is not sizeof
taking two arguments. sizeof
is an operator, not a function.
Consider that (0, arr)
is an expression using the comma operator, and everything else falls into place.
sizeof
doesn't take two arguments. But it's not a function, either,
so the (...)
don't delimit function arguments, they're just an
optional part of the syntax, and enforce grouping. When you write
sizeof(0, arr)
, the argument to sizeof
is the single expression 0,
arr
. A single expression with a comma operator, which evaluates the
expression to the left of the comma, throws out its value (but not its
side effects), then evaluates the expression to the right of the comma,
and uses its value as the value of the complete expression.
I'm not sure about C, but this could be a difference between the
langauges. In C++, the array-to-pointer conversion doesn't occur unless
it is needed; in C, if I recall correctly, the standard says that it
always takes place except in certain contexts. Including as the
operator of sizeof
. In this case, since the comma operator doesn't
have an constraints with regards to the types of its operands, the
array-to-pointer conversion doesn't take place in C++. In C, an
operatand of the comma operator isn't listed in the exceptions, so the
array-to-pointer conversion does take place. (In this case, the array
is an operand of the comma operator, and not of sizeof
.)
The best way to see what could be going on here is look at the grammar in the standard. If we look at the draft C99 standard section 6.5.3
Unary operators paragraph 1 we can see that the grammar for sizeof is:
sizeof unary-expression
sizeof ( type-name )
So the second one does not apply but how does the sizeof unary-expression
apply in this case? If we look at section A.2.1
Expressions from the draft standard and work through the grammar like so:
unary-expression -> postfix-expression -> primary-expression -> ( expression )
we get the parenthesizes around an expression and now we just have to look at the grammar for comma operator from section 6.5.17
Comma operator and we see:
expression:
assignment-expression
expression , assignment-expression
So we have now have:
sizeof( expression , assignment-expression )
^
|
comma operator
both expression and assignment-expression can take us to primary-expression which has the following grammar:
primary-expression:
identifier
constant
string-literal
( expression )
and 0
is a constant and arr
is an identifier so we have:
sizeof( constant , identifier )
So what does the comma operator do here? Section 6.5.17
paragraph 2 says:
The left operand of a comma operator is evaluated as a void expression; there is a sequence point after its evaluation. Then the right operand is evaluated; the result has its type and value.97)
since the comma operator is not one of the exceptions where a array is not converted to a pointer it yields a pointer(this is covered in section 6.3.2.1
Lvalues, arrays, and function designators) which means we end up with:
sizeof( char * )
In C++ the grammar is pretty similar so we end in the same place but the comma operators works differently. The C++ draft standard section 5.18
Comma operator says:
[...]The type and value of the result are the type and value of the right operand; the result is of the same value category as its right operand[...]
so and array-to-pointer conversion is not not required and so we end up with:
sizeof( char[100] )
As several have already said, and I want to add only one thing, sizeof is an operator taking either an expression or a cast expression. For this reason I took the habit to write paranthesis to a sizeof only if it is a cast expression.
char *arr;
struct xxx { ... } v;
I will write
sizeof arr
sizeof v
but
sizeof (struct xxx) /* Note the space after the sizeof, it's important */
sizeof (char *)
I do the same with return
no parenthesis, as it is not a function call, and if I put parenthesis it's because the expression following needs them.
来源:https://stackoverflow.com/questions/6331588/sizeof-taking-two-arguments