Почему sizeof (my_arr) [0] компилируется и равен sizeof (my_arr [0])? - программирование

Почему sizeof (my_arr) [0] компилируется и равен sizeof (my_arr [0])?

Почему этот код компилируется?

_Static uint32_t my_arr[2];
_Static_assert(sizeof(my_arr) == 8, "");
_Static_assert(sizeof(my_arr[0]) == 4, "");
_Static_assert(sizeof(my_arr)[0] == 4, "");

Первые два утверждения, очевидно, правильны, но я ожидал, что последняя строка не сработает, поскольку я понимаю, что sizeof() должен оценивать целочисленный литерал, который нельзя рассматривать как массив. Другими словами, он потерпел бы неудачу так же, как и следующая строка:

_Static_assert(4[0] == 4, "");

Интересно, что следующее действительно не удается скомпилировать (что должно делать то же самое, нет?):

_Static_assert(*sizeof(my_arr) == 4, "");

error: недопустимый аргумент типа унарного '*' (есть "long unsigned int" ) _Static_assert (* sizeof (my_arr) == 4, "");

Если это важно, я использую gcc 5.3.0

4b9b3361

Ответ 1

sizeof не является функцией. Это унарный оператор, такой как ! или ~.

sizeof(my_arr)[0] анализирует как sizeof (my_arr)[0], который просто sizeof my_arr[0] с резервными скобками.

Это так же, как !(my_arr)[0] анализирует как !(my_arr[0]).

В общем случае операторы постфикса имеют более высокий приоритет, чем префиксные операторы в C. sizeof *a[i]++ анализируются как sizeof (*((a[i])++)) (операторы postfix [] и ++ применяются сначала к a, тогда префиксные операторы * > и sizeof).

(Это версия выражения sizeof. Также существует версия типа, которая принимает имя типа в скобках: sizeof (TYPE). В этом случае требуется использовать parens и часть синтаксиса sizeof.)

Ответ 2

sizeof имеет две "версии": sizeof(type name) и sizeof expression. Первая требует пары () вокруг своего аргумента. Но последний - тот, у которого есть выражение как аргумент, не имеет () вокруг своего аргумента. Независимо от того, что (), которое вы используете в аргументе, рассматривается как часть выражения аргумента, а не как часть синтаксиса sizeof.

Поскольку my_arr известен компилятору как имя объекта, а не имя типа, ваш sizeof(my_arr)[0] фактически рассматривается компилятором как sizeof, примененным к выражению: sizeof (my_arr)[0], где (my_arr)[0] выражение аргумента. (), окружающий имя массива, является излишним. Все выражение интерпретируется как sizeof my_arr[0]. Это эквивалентно предыдущему sizeof(my_arr[0]).

(Это значит, BTW, что предыдущий sizeof(my_arr[0]) также содержит пару лишних ().)

Это довольно распространенное заблуждение, что синтаксис sizeof так или иначе требует пары () вокруг его аргумента. Это заблуждение - это то, что вводит в заблуждение людей интуицию при интерпретации таких выражений, как sizeof(my_arr)[0].

Ответ 3

[] имеют более высокую точность, чем sizeof. Итак, sizeof(my_arr)[0] совпадает с sizeof((my_arr)[0]).

Здесь - ссылка на таблицу приоритетов.

Ответ 4

Вы используете версию оператора sizeof, которая принимает выражение как параметр. В отличие от того, который принимает тип, он не требует скобок. Следовательно, операнд просто (my_arr)[0], причем круглые скобки являются избыточными.