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 без скобок, поскольку это не вызов функции, и если я помещаю его в скобки, потому что для этого требуется следующее выражение.