Поведение оператора "запятая" оператора 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.