Reputation: 92854
Consider the following code:
#include <stdio.h>
int main(void)
{
int a[10];
printf("%d",(int)sizeof(a)); //prints 10*sizeof(int) (40 on my compiler)
printf("%d",(int)sizeof(a-3)); //prints sizeof(int) (4 on my compiler)
}
I know that sizeof()
is a compile time operator but I was surprised to see the output of second printf()
. What could be the reason? Is there an implicit conversion of the argument of sizeof()
from an array-type to an integer type?
Upvotes: 12
Views: 564
Reputation: 96091
The sizeof
operator doesn't evaluate its argument, it only looks at the type of its operand.
Let's say you have an array a
with type "array [N] of type T". Then, in most cases, the type of the name a
is "pointer to T" (T *
), and the value of the pointer is the address of the first element of the array (&a[0]
). That is, the name of an array "decays" to a pointer to its first element. The "decaying" doesn't happen in the following cases:
a
is used with the address-of (&
) operator,a
(it is illegal to assign to arrays in C), anda
is the operand of the sizeof
operator.So, sizeof a
gives you N
times sizeof(T)
.
When you do sizeof(a-3)
, the type of the operand to sizeof
is determined by the expression a-3
. Since a
in a-3
is used in a value context (i.e., none of the three contexts above), its type is "pointer to int", and the name a
decays to a pointer to a[0]
. As such, calculating a-3
is undefined behavior, but since sizeof
doesn't evaluate its argument, a-3
is used only to determine the type of the operand, so the code is OK (see the first link above for more).
From the above, sizeof(a-3)
is equivalent to sizeof(int *)
, which is 4 on your computer.
The "conversion" is due to the subtraction operator. You can see a similar, and perhaps more surprising, result with the comma operator:
printf("%zu\n", sizeof(1, a));
will also print sizeof(int *)
, because of the comma operator resulting in a
getting used in a value context.
Upvotes: 29
Reputation: 57036
sizeof()
returns the size of a type, so the type is what's important.
It also shouldn't be printed with %d
. At the very least, explicitly cast it to unsigned long
or unsigned long long
and use the appropriate format specifier. When teaching C, I had a student get the wrong answer by printing size_t
with %d
as the textbook mistakenly said to do.
Anyway, a
is an array type. In C, array types decay to pointer types if you do almost anything with them or sneeze loudly, so almost anything you do to a
will yield a pointer type. As you've found out, adding or subtracting a number will decay. (After all, an array can't be used in arithmetic, but a pointer can.)
Upvotes: 1
Reputation: 170479
Nope, in the second case the argument is interpreted as an int*
pointer which happens to also have size equal to 4 on your machine.
Upvotes: 1
Reputation: 8053
(a-3)
has type int*
, and it prints you sizeof(int*)
which is 4 on your platform.
And note that sizeof()
is no longer compile-time constant in C99 (due to variadic-length arrays).
Upvotes: 5