Sizeof принимает два аргумента
В C.1.3 С++ IS (2003. Он также в С++ 11 IS), стандарт указывает разницу между ISO C и С++; а именно для
char arr[100];
sizeof(0, arr)
возвращает sizeof(char*)
в C, но 100
в С++.
Я не могу найти документацию для sizeof
с двумя аргументами. Очевидным резервным является запятый оператор, но я так не думаю: sizeof(arr)
в C есть 100
; sizeof(0, arr)
- sizeof(char*)
. Оба sizeof(0, arr)
и sizeof(arr)
являются 100
в С++.
В этом контексте может отсутствовать вся суть IS. Может ли кто-нибудь помочь? Это похоже на вопрос, обсуждавшийся еще в '09, но никто не ссылался на ИС, и я не думаю, что был дан правильный ответ.
Изменить. На самом деле IS говорит о запятой. Поэтому по какой-то причине (0, arr)
возвращает a char*
в C, но a char[100]
в С++. Почему?
Ответы
Ответ 1
В C затем массив разлагается на указатель из-за различной спецификации оператора запятой относительно rvalues и lvalues (а не единственное место, где такая разница может быть найдена). В С++ массив остается массивом, что дает правильный результат.
Ответ 2
В C оператор-запятая не производит lvalue, поэтому массив arr
, который является lvalue, распадается на тип указателя, который является rvalue (в данном случае). Таким образом, sizeof(0,arr)
становится эквивалентным sizeof(char*)
, из-за преобразования lvalue-to-r.
Но в С++ оператор запятой производит lvalue. Нет преобразования lvalue-to-rvalue. Итак, sizeof(0,arr)
остается таким же, что эквивалентно sizeof(char[100])
.
Кстати, sizeof
не является функцией, ее оператором. Таким образом, вполне допустимо С++ (и C, если вы представляете printf
вместо cout
):
int a[100], b[200], c[300], d[400];
cout << sizeof(a,b,c,d) << endl;
Демо: http://www.ideone.com/CtEhn
Вы можете подумать, что я прошел 4 операнда до sizeof
, но это неправильно. sizeof
действует на результат операторов запятой. И из-за многих операторов запятой вы видите много операндов.
4 операнда <= 3 запятых операторов; как и в 1+2+3+4
, есть 3 оператора, 4 операнда.
Вышеупомянутое эквивалентно следующему (действителен в С++ 0x):
auto & result = (a,b,c,d); //first all comma operators operate on the operands.
cout << sizeof (result) << endl; //sizeof operates on the result
Демо: http://www.ideone.com/07VNf
Итак, это оператор запятой, который заставляет вас почувствовать, что есть много аргументов. Здесь запятая - это оператор, но в вызове функции запятая НЕ является оператором, просто разделителем аргументов.
function(a,b,c,d); //here comma acts a separator, not operator.
Итак, sizeof(a,b,c,d)
работает по типу результата операторов ,
точно так же, sizeof(1+2+3+4)
работает по типу результата операторов +
.
Также обратите внимание, что не может писать sizeof(int, char, short)
, потому что оператор-запятая не может работать с типами. Он работает только по стоимости. Я думаю, sizeof
является единственным оператором в C и С++, который также может работать и с типами. В С++ существует еще один оператор, который может работать с типами. Его имя typeid
.
Ответ 3
Это оператор запятой. И разница, о которой вы говорите, абсолютно не имеет отношения к sizeof
. Разница действительно в значениях lvalue-to-rvalue, от массива до указателя и аналогичных поведениях распада между C и С++ языками.
C-язык в этом отношении довольно сдержанный: массивы распадаются на указатели практически сразу (за исключением очень небольшого количества конкретных контекстов), поэтому результат выражения 0, arr
имеет тип char *
. Это эквивалентно 0, (char *) arr
.
В С++ языковые массивы сохраняют их "массивность" намного дольше. При использовании в контексте ,
массивы операторов не распадаются на указатели (а lvalues не убывают до rvalues), поэтому в С++ тип выражения 0, arr
все еще char[100]
.
Вот что объясняет разницу в поведении sizeof
в этом примере. Оператор ?:
- еще один пример оператора, который демонстрирует аналогичную разницу в поведении распада, т.е. sizeof(0 ? arr : arr)
даст вам разные результаты в C и С++. В принципе, все это проистекает из того факта, что операторы C обычно не сохраняют lvalueness своих операндов. Для демонстрации этого поведения можно использовать множество операторов.
Ответ 4
Это не sizeof
с двумя аргументами. sizeof
- это оператор, а не функция.
Считаем, что (0, arr)
- выражение, использующее оператор запятой, и все остальное встает на свои места.
Ответ 5
sizeof
не принимает два аргумента. Но это не функция,
поэтому (...)
не ограничивают аргументы функции, они просто
необязательная часть синтаксиса и принудительная группировка. Когда вы пишете
sizeof(0, arr)
, аргументом sizeof
является одиночное выражение 0,
arr
. Одно выражение с оператором запятой, которое оценивает
выражение слева от запятой, выбрасывает его значение (но не его
побочные эффекты), затем оценивает выражение справа от запятой,
и использует его значение как значение полного выражения.
Я не уверен в C, но это может быть разница между
. охват языков В С++ преобразование между массивами и указателями не происходит, если
необходимо; в C, если я правильно помню, стандарт говорит, что это
всегда происходит, за исключением определенных контекстов. Включая
оператора sizeof
. В этом случае, поскольку оператор запятой не
имеют ограничения в отношении типов своих операндов,
преобразование массива в указатель не выполняется в С++. В C
оператор запятой не указан в исключениях, поэтому
преобразование массива в указатель имеет место. (В этом случае массив
является операндом оператора запятой, а не sizeof
.)
Ответ 6
Лучший способ увидеть, что может происходить здесь, - это посмотреть на грамматику в стандарте. Если мы посмотрим на проект стандартного раздела C99 6.5.3
Unary, параграф 1, мы можем видеть, что грамматика для sizeof:
sizeof unary-expression
sizeof ( type-name )
Итак, второй не применяется, но как применяется sizeof unary-expression
в этом случае? Если мы посмотрим на раздел A.2.1
Выражения из черновика и проработаем через такую грамматику:
unary-expression -> postfix-expression -> primary-expression -> ( expression )
мы получаем круглые скобки вокруг выражения, и теперь нам просто нужно посмотреть на грамматику для оператора запятой из секции 6.5.17
Comma, и мы видим:
expression:
assignment-expression
expression , assignment-expression
Итак, у нас теперь есть:
sizeof( expression , assignment-expression )
^
|
comma operator
выражение и выражение-присваивание могут привести нас к первичному выражению, которое имеет следующую грамматику:
primary-expression:
identifier
constant
string-literal
( expression )
и 0
является константой, а arr
является идентификатором, поэтому мы имеем:
sizeof( constant , identifier )
Итак, что здесь делает оператор запятой? Раздел 6.5.17
параграф 2 гласит:
Левый операнд оператора запятой оценивается как выражение void; Eсть после его оценки. Затем оценивается правый операнд; результат имеет свой тип и значение. 97)
поскольку оператор запятой не является одним из исключений, когда массив не преобразован в указатель, он дает указатель (это описано в разделе 6.3.2.1
Lvalues, массивы и указатели функций), что означает, что мы заканчиваем:
sizeof( char * )
В С++ грамматика довольно похожа, поэтому мы заканчиваем там же, но операторы запятой работают по-разному. Раздел стандартного текста С++ 5.18
Оператор Comma говорит:
[...] Тип и значение результата - это тип и значение правильного операнда; результат имеет ту же категорию значений, что и ее правый операнд [...]
поэтому преобразование массива в указатель не требуется, и поэтому мы получаем:
sizeof( char[100] )
Ответ 7
Как уже сказано несколько, и я хочу добавить только одно, sizeof - оператор, принимающий либо выражение, либо выраженное выражение.
По этой причине я привык писать paranthesis до sizeof только, если это выраженное выражение.
char *arr;
struct xxx { ... } v;
Я напишу
sizeof arr
sizeof v
но
sizeof (struct xxx) /* Note the space after the sizeof, it important */
sizeof (char *)
Я делаю то же самое с return
без скобок, поскольку это не вызов функции, и если я помещаю его в скобки, потому что для этого требуется следующее выражение.