Мне трудно понять поведение sizeof
при задании тройного выражения.
#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;
}
В этом примере (проверенном с gcc 4.4.3 и 4.7.2, скомпилированным с -std=c99
), b равно 9 (8 символов + неявный '\0'
), c - 1 (неявный '\0'
). a по какой-то причине 4.
Я ожидал бы, что a будет либо 9, либо 1, в зависимости от того, является ли argc больше 1. Я думал, что, возможно, строковые литералы преобразуются в указатели перед передачей на sizeof
, вызывая sizeof(char*)
равным 4.
Я попытался заменить STRING
и ""
на char массивы...
char x[] = "";
char y[] = "a string";
int a = sizeof(argc > 1 ? x : y);
... но я получил те же результаты (a = 4, b = 9, c = 1).
Затем я попытался погрузиться в спецификацию C99, но я не нашел в ней каких-либо очевидных объяснений. Из любопытства я также попытался изменить изменения x и y на другие типы:
-
char
иlong long int
: a становится 8 - оба
short
или обаchar
: a становится 4
Итак, определенно происходит какое-то преобразование, но я изо всех сил пытаюсь найти какое-либо официальное объяснение. Я могу себе представить, что это произойдет с арифметическими типами (я смутно знаю, что много продвижений происходит, когда они задействованы), но я не понимаю, почему строковый литерал, возвращаемый тернарным выражением, будет преобразуется в размер 4.
NB: на этом аппарате sizeof(int) == sizeof(foo*) == 4
.
Последующий
Спасибо за ребята. Понимание того, как работают sizeof
и ?:
, побудило меня попробовать еще несколько типов mashup и посмотреть, как реагирует компилятор. Я редактирую их для полноты:
foo* x = NULL; /* or foo x[] = {} */
int y = 0; /* or any integer type */
int a = sizeof(argc > 1 ? x : y);
Допустимые значения warning: pointer/integer type mismatch in conditional expression [enabled by default]
и a == sizeof(foo*)
.
С foo x[], bar y[]
, foo* x, bar* y
или foo* x, bar y[]
предупреждение становится pointer type mismatch
. Предупреждение при использовании void*
.
float x = 0; /* or any floating-point type */
int y = 0; /* or any integer type */
int a = sizeof(argc > 1 ? x : y);
Не дает никаких предупреждений и a == sizeof(x)
(т.е. тип с плавающей запятой).
float x = 0; /* or any floating-point type */
foo* y = NULL; /* or foo y[] = {} */
int a = sizeof(argc > 1 ? x : y);
Допустимые значения error: type mismatch in conditional expression
.
Если я когда-либо прочитал спецификацию, я обязательно отредактирую этот вопрос, чтобы указать на соответствующие части.