Поведение оператора "запятая" оператора sizeof() в C
Я написал код оператора sizeof
. Если я напишу что-то вроде:
#include <stdio.h>
int main() {
char a[20];
printf("%zu\n", sizeof(a));
return 0;
}
Вывод:
20 // Ok, it fine
Но, если я использую оператор запятая следующим образом:
#include <stdio.h>
int main() {
char a[20];
char b;
printf("%zu\n", sizeof(b, a));
return 0;
}
Вывод:
8 // Why the output 8?
Итак, у меня есть вопросы:
- Почему компилятор дает вывод
8
во втором примере?
- Каково поведение оператора
comma
в операторе sizeof()
?
Ответы
Ответ 1
Оператор запятой не имеет особого значения для sizeof
.
sizeof(b, a)
проверяет полное выражение (b, a)
, выдает результирующий тип и вычисляет размер этого типа без фактической оценки (b , a)
. Как отмечено chqrlie в комментариях, ()
являются частью выражения, для которого оценивается размер (результата).
В этом случае b
является char
, а a
является массивом. Если выражение b, a
должно быть оценено, сначала будет оценено b
, результат будет отброшен. Затем a
преобразуется в указатель (char *
) со значением, равным &a[0]
, который был бы результатом выражения (b, a)
.
Так как результат b, a
имеет тип char *
, sizeof(b,a)
равен sizeof (char *)
. Это значение, определенное для реализации, но для вашего компилятора имеет значение 8
(что, вероятно, означает, что код создается как 64-разрядное приложение).
Ответ 2
В большинстве случаев массивы распадаются на указатели. Таким образом, тип b,a
с оператором запятой - это char*
(а не a char[20]
). А указатели на вашем компьютере - 8 байтов.
Кстати, я думаю, что использование sizeof
для некоторого оператора запятой действительно запутывает читателя. Я рекомендую использовать sizeof
для простых выражений или типов.
(и я только что обнаружил, что это одно из сложных различий между C и С++, см. это объяснение)
Ответ 3
Язык C - это язык, отбрасывающий lvalue. Оператор Comma в C не дает lvalue и не сохраняет "массивность" массивов. Это означает, что когда правый операнд является массивом, он сразу же подвергается преобразованию между массивами и указателями. По этой причине в C результатом вашего оператора запятой является rvalue типа char *
. Это то, к чему вы применили свой sizeof
to. И именно поэтому вы получаете 8
в качестве результата, который является размером указателя на вашей платформе.
Язык С++ - это язык, сохраняющий lvalue. Правый операнд оператора запятой в С++ не подвергается преобразованию lvalue-rvalue, и в случае, если операндом является массив, он сохраняет свою плотность и тип массива. В С++ результатом вашего оператора запятой является lvalue типа char[20]
. Это то, к чему вы применили свой sizeof
to. И именно поэтому вы получаете 20
.
Ответ 4
sizeof
определяет размер по типу его операнда. В sizeof(a)
a
не будет распадаться на указатель на первый элемент, а тип a
будет char[20]
. В sizeof(b, a)
a
является правильным операндом оператора запятой и в этом контексте он будет распадаться на указатель на его первый элемент, а тип выражения b , a
будет char *
. Поэтому sizeof(b, a)
вернет размер типа char *
.
В С++ результат оператора ,
является lvalue (в отличие от C, где он дает rvalue). В этом случае sizeof(b, a)
вернет размер массива a
.