Чому sizeof (my_arr) [0] складається і дорівнює sizeof (my_arr [0])?


129

Чому цей код складається?

_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, "");

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

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

Цікаво, що наступне дійсно не вдається скласти (що має робити те саме, ні?):

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

помилка: недійсний аргумент типу unary '*' (мають 'давно непідписаний int') _Static_assert (* sizeof (my_arr) == 4, "");

Якщо це має значення, я використовую gcc 5.3.0


15
Я підозрюю ( sizeof( my_arr ) )[ 0 ]невдачі.
Ендрю Генле

Нещодавній дублікат має ще одну зміну цього сюрпризу синтаксису: Чому компілюється sizeof (x) ++?
Пітер Кордес

Відповіді:


197

sizeofне є функцією. Це одинарний оператор, як !або ~.

sizeof(my_arr)[0]розбирає як sizeof (my_arr)[0], що просто sizeof my_arr[0]із зайвими дужками.

Це так само, як і !(my_arr)[0]розбори !(my_arr[0]).

Взагалі, оператори постфікса мають вищий пріоритет, ніж оператори префіксів у C. sizeof *a[i]++parses як sizeof (*((a[i])++))(оператори постфікса []і ++застосовуються aспочатку, потім оператори префікса *та sizeof).

(Це версія вираження sizeofТам також версія типу, яка приймає в дужках імені типу :. sizeof (TYPE). У цьому випадку круглі дужки будуть необхідні і частина sizeofсинтаксису.)


14
Я точно знав, що sizeof є одинарним оператором і не функцією, але повністю забув. Вупи. Дякую за детальне пояснення. Факт, що [] є вищим пріоритетом, ніж *, цікавий незалежно.
бгомберг

@melpomene Цікаво. Я ніколи не думав sizeofбути одинаковим оператором.
mutantkeyboard

5
Ви не маєте на увазі "... parses as sizeof (my_arr[0])"? Просто додавання пробілу насправді нічого не змінює.
Бернхард Баркер

Я б рекомендував sizeof((my_array)[0])замість цього
bolov


46

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].


1
Перша версія існує так, що ви можете взагалі перевірити розмір цілого числа на машині (з тильної сторони, коли не було навіть 64-бітних машин!), Але intце не є дійсним виразом, тому ви не можете використовувати друга форма з нею.
NH.

25

[]мають більш високий , ніж precendence sizeof. Так sizeof(my_arr)[0]це те саме, що sizeof((my_arr)[0]).

Ось посилання на таблицю пріоритету.


8

Ви використовуєте версію sizeofоператора, яка приймає вираз як параметр. На відміну від типу, який приймає тип, він не потребує дужок. Отже, операнд є простим (my_arr)[0], дужки є надмірними.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.