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
andlong long int
: a becomes 8- both
short
or bothchar
: a becomes 4
So 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
.
Follow-up
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.