Context
The standard says (C17, 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. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.
Confusingly, the wording doesn't distinguish between sizeof
's two syntactic contexts:
sizeof
unary-expressionsizeof(
type-name)
I believe that type-name technically doesn't "have" a type, but rather "denotes" (names, specifies) one. Also, in the case of a type name as the argument, I would intuitively have phrased this in terms of evaluating all assignment-expressions within it – if not for accuracy, then for clarity.
In any event, I understand this wording to mean that in the case of sizeof(type)
, all expressions within type
are evaluated exactly if (ie: if and only if) type
denotes a VLA (variable-length array) type.
Problem
With the above in mind, the following code's last printf
statement has surprising results:
#include <stdio.h>
void f(int i) {
printf("side effect %d; ", i);
}
int main(void) {
int n = 9;
int a[n];
printf("%zu\n", sizeof a); // 36
printf("%zu\n", sizeof a[n++]); // 4
printf("%d\n", n); // 9
printf("%zu\n", sizeof(int [n++])); // 36
printf("%d\n", n); // 10
printf("%zu\n", sizeof(int [(f(0), 100)]));
// side effect 0; 400 (type of operand: int, a non-VLA type)
return 0;
}
(The argument int i
of f
– omitted in the question title – is intended for debugging purposes and for playing around, if one wants to distinguish different calls to that function.)
- Plain and simple:
int [(f(0), 100)]
denotes typeint [100]
, which is not a VLA type. So: Why doesf(0)
get evaluated? - More generally: What are the exact conditions under which
type_name
(or expressions within it) insizeof(type_name)
are evaluated?
Incidentally, sizeof(int [f(0), 100])
(without parentheses surrounding the comma expression denoting the array size) leads to an error, which I discuss in the following question: Why must a comma expression used as an array size be enclosed in parentheses if part of an array declarator?
Other references
Relevant places in the standard (C17 draft) for where the syntax of array declarators is discussed include: 6.7.7 ¶1, 6.7.6.2 ¶3.
This answer by Keith Thompson to a question about VLAs is relevant. But note that my question is not about VLAs per se (even though it uses them in the code above for contrastive purposes).
int [100]
is an array type. Its type is, quite literally,int [100]
. That is basic to C and has always been that way. If you declareint a[100]
, then the type ofa
isint [100]
. It's an array type. Second, in this context(f(0), 100)
is an expression. The comma is a comma operator. When evaluated, it first evaluatesf(0)
. It then evaluates100
, which of course is just100
. – Kenwricksizeof
is supposed to be evaluated at compile-time, with only VLA arguments (or presumably types denoting such) triggering an exception. – Trifocalsizeof
is a variable-length array, since(f(0), 100)
is not a constant expression. Yes, the result will always be 100, but the first argument could have side effects, and in any case the compiler is not required to treat it as a constant expression. Constant expressions cannot contain function calls. Since it's not a constant expression, the declaration is for a VLA. You can test it by trying to use it in astatic
declaration, e.g.static int a[(f(0), 100)];
. You'll get an error. – Kenwrickprintf("%zu\n", sizeof *(f(1), &a)); // side effect 1; 36
printf("%zu\n", sizeof (f(2), n)); // 4
– Trifocal(f(0), 100)
is not a constant expression. Period. Everything follows from that. What is it that you still don't understand? – Kenwrick(
*type-name*)
, then it is a type, so it is evaluated… – Selectionsizeof
makes very little sense. It is enough to evaluate only size-expressions present in declarations of VLA-types. There is discussion about the actual meaning evaluation ofsizeof
. See www9.open-std.org/JTC1/SC22/WG14/www/docs/n3187.htm – Anissa