Почему sizeof int неправильный, а sizeof (int) правильный?

97

Мы знаем, что sizeofэто оператор, используемый для вычисления размера любого типа данных и выражения, и когда операнд является выражением, скобки можно опустить.

int main()
{
        int a;

        sizeof int;
        sizeof( int );
        sizeof a;
        sizeof( a );

        return 0;
}

первое использование sizeofневерно, тогда как другие верны.

При компиляции с использованием gcc будет выдано следующее сообщение об ошибке:

main.c:5:9: error: expected expression before int

У меня вопрос, почему стандарт C не допускает такого рода операции. Вызовет sizeof intли двусмысленность?

Ишу Фанг
источник
5
Самое смешное, что не все выражения принимаются без скобок: попробуйте sizeof (int)a.
Фред Фу,
2
@MikkelK .: OP спрашивает причину стандартных цитат, он уже знает цитаты, упомянутые в отмеченном ответе.
Alok Save
2
@Lundin: sizeof +(int)aимеет преимущество перед *&фактической компиляцией ;-)
Стив Джессоп
2
@SteveJessop Ага, это не lvalue. Хотя, как ни странно, он компилировался на Embarcadero C ++. В любом случае, я считаю, что мы только что нашли применение унарному оператору +! Это должно быть впервые в истории программирования на C :)
Lundin
2
@Lundin: Вы все равно должны быть осторожны с унарными +. Например, sizeof +(char)a == sizeof(int)из-за целочисленного продвижения, вероятно, будет менее подвержено ошибкам просто заключить круглые скобки, если есть хоть какое-то беспокойство по поводу выражения, размер которого вы пытаетесь взять. Так что я не уверен, что зашел бы так далеко, чтобы назвать это «использование», хотя признаю, что использовал его ...
Стив Джессоп

Ответы:

101

Следующее может быть двусмысленным:

sizeof int * + 1

Это (sizeof (int*)) + 1или (sizeof(int)) * (+1)?

Очевидно, что язык C мог бы ввести правило для разрешения двусмысленности, но я могу представить, почему это не беспокоило. В существующем языке спецификатор типа никогда не появляется в выражении «голым», и поэтому нет необходимости в правилах для определения того, *является ли эта секунда частью типа или арифметическим оператором.

Существующая грамматика уже устраняет потенциальную двусмысленность sizeof (int *) + 1. Это (sizeof(int*))+1, не sizeof((int*)(+1)) .

В C ++ есть несколько похожая проблема, которую нужно решить с помощью синтаксиса приведения в стиле функции. Вы можете писать int(0)и вы можете писать typedef int *intptr; intptr(0);, но вы не можете писать int*(0). В этом случае решение состоит в том, что «голый» тип должен быть простым именем типа, это не может быть просто любой старый идентификатор типа, в котором могут быть пробелы или конечная пунктуация. Может быть, это sizeofмогло быть определено с таким же ограничением, я не уверен.

Стив Джессоп
источник
1
В C ++ new int*(X)это было бы неоднозначно, если бы в C ++ не было указано, что оператор new принимает самую длинную строку, которая может быть типом. Думаю, в C ++ они могли бы сделать то же самое с sizeof. Но в C ++ вы можете сказать, sizeof int()что тогда было бы неоднозначным (тип или значение, инициализированное int?).
Йоханнес Шауб - лит
@ JohannesSchaub-litb: Ммм, так что, возможно, C ++ мог бы сказать, что тип предпочтительнее, если его можно проанализировать, иначе это выражение. Неоднозначность будет решена , но sizeof int()будет плохо сформирована ( «не operator()для size_t»), который я ожидал бы нежелательно!
Стив Джессоп,
32

От стандарта C99

6.5.3.4.2 оператор дает размер (в байтах) своего операнда, который может быть выражение в скобках или имя типа.
sizeof

В вашем случае intнет ни выражения, ни имени в скобках.

Джайнендра
источник
10
Я не понимаю, почему это получает 7 голосов. Как и три удаленных ответа, он просто повторяет правило, а не объясняет, почему оно существует.
Фред Фу,
8
@larsmans, да, согласен с тобой. Хотя он продолжает повторять правило, но, по крайней мере, дает фрагмент авторизации для чтения.
Ишу Фанг,
3
@larsmans Если мы начнем оправдывать каждое решение, принятое в C99, мы будем здесь весь год. Цитирование стандарта - лучший способ завершить обсуждение.
Перри
1
@Perry: если вам не нравятся такие вопросы, вы можете проголосовать, чтобы закрыть вопрос как аргумент.
Фред Фу,
4
Как непрактикующий в C ++, даже я понимаю этот ответ, но не уверен, в чем проблема, если вы можете читать и понимать английский.
Кев
6

Есть два способа использовать оператор sizeof в C. Синтаксис следующий:

C11 6.5.3 Unary operators
...
sizeof unary-expression
sizeof ( type-name )

Каждый раз, когда вы используете тип в качестве операнда, вы должны иметь круглые скобки в соответствии с определением синтаксиса языка. Если вы используете sizeof в выражении, скобки не нужны.

Стандарт C дает один такой пример того, где вы можете использовать его в выражении:

sizeof array / sizeof array[0]

Однако для согласованности и во избежание ошибок, связанных с приоритетом операторов, я лично посоветовал бы всегда использовать () независимо от ситуации.

Лундин
источник
@ JohannesSchaub-litb Я согласен с тем, что это не дает никакого объяснения тому, как рассуждал комитет по стандартизации C, когда они указали стандарт C90. Вам придется их спросить ... Он отвечает без какого-либо объяснения, однако C не позволяет этого, поскольку синтаксис соответствует указанному в 6.5.3. OP также, похоже, не знал о разнице между sizeof expressionи sizeof(type), что объясняется в этом ответе.
Lundin
(Для протокола, я только что прочитал обоснования C90 и C11, и ни один из них не дает никаких объяснений.)
Lundin
Я подозреваю, что для этого нет необходимого объяснения, просто так решили сделать оригинальные разработчики C. Может быть, это упростило работу раннему парсеру. Я собирался опубликовать ответ о том, что typedef и переменные используют одно и то же пространство имен, но это не препятствует разрешению первого синтаксиса; ему просто нужны правила синтаксического анализа, чтобы сказать, что он предпочитает переменную, когда нет скобок, предпочитает тип, когда они есть, и любая форма может использоваться, если имя однозначно. Поскольку нет необходимости его менять, комитеты по стандартам оставили его в покое.
Barmar