I have a hard time understanding sizeof
's behaviour when given a ternary expression.
#define STRING "a string"
int main(int argc, char** argv)
{
int a = sizeof(argc > 1 ? STRING : "");
int b = sizeof(STRING);
int c = sizeof("");
printf("%d\n" "%d\n" "%d\n", a, b, c);
return 0;
}
In this example (tested with gcc 4.4.3 and 4.7.2, compiled with -std=c99
), b is 9 (8 characters + implicit '\0'
), c is 1 (implicit '\0'
). a, for some reason, is 4.
I would expect a to be either 9 or 1, based on whether argc is greater than 1. I thought maybe the string literals get converted to pointers before being passed to sizeof
, causing sizeof(char*)
to be 4.
I tried replacing STRING
and ""
by char arrays...
char x[] = "";
char y[] = "a string";
int a = sizeof(argc > 1 ? x : y);
... but I got the same results (a=4, b=9, c=1).
Then I tried to dive into the C99 spec, but I did not find any obvious explanation in it. Out of curiosity I also tried changing changing x and y to other types:
char
and long long int
: a becomes 8short
or both char
: a becomes 4So there's definitely some sort of conversion going on, but I struggle to find any official explanation. I can sort of imagine that this would happen with arithmetic types (I'm vaguely aware there's plenty of promotions going on when those are involved), but I don't see why a string literal returned by a ternary expression would be converted to something of size 4.
NB: on this machine sizeof(int) == sizeof(foo*) == 4
.
Thanks for the pointers guys. Understanding how sizeof
and ?:
work actually led me to try a few more type mashups and see how the compiler reacted. I'm editing them in for completeness' sake:
foo* x = NULL; /* or foo x[] = {} */
int y = 0; /* or any integer type */
int a = sizeof(argc > 1 ? x : y);
Yields warning: pointer/integer type mismatch in conditional expression [enabled by default]
, and a == sizeof(foo*)
.
With foo x[], bar y[]
, foo* x, bar* y
or foo* x, bar y[]
, the warning becomes pointer type mismatch
. No warning when using a void*
.
float x = 0; /* or any floating-point type */
int y = 0; /* or any integer type */
int a = sizeof(argc > 1 ? x : y);
Yields no warning, and a == sizeof(x)
(that is, the floating-point type).
float x = 0; /* or any floating-point type */
foo* y = NULL; /* or foo y[] = {} */
int a = sizeof(argc > 1 ? x : y);
Yields error: type mismatch in conditional expression
.
If I ever read the spec completely I'll make sure to edit this question to point to the relevant parts.
You have to understand expressions, which are the core component of the language.
Every expression has a type. For an expression e
, sizeof e
is the size of the type of the value of the expression e
.
The expression a ? b : c
has a type. The type is the common type of the two operand expressions b
and c
.
In your example, the common type of char[9]
and char[1]
is char *
(both array-valued expressions decay to a pointer to the first element). (In C++, the rules for string literals are different and there is a const
everywhere.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With