Sizeof принимает два аргумента

196
15

В 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] в С++. Почему?

спросил(а) 2011-06-13T17:11:00+04:00 8 лет, 8 месяцев назад
1
Решение
170

В C затем массив разлагается на указатель из-за различной спецификации оператора запятой относительно rvalues ​​и lvalues ​​(а не единственное место, где такая разница может быть найдена). В С++ массив остается массивом, что дает правильный результат.

ответил(а) 2011-06-13T17:16:00+04:00 8 лет, 8 месяцев назад
228

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

ответил(а) 2011-06-13T17:19:00+04:00 8 лет, 8 месяцев назад
95

Это оператор запятой. И разница, о которой вы говорите, абсолютно не имеет отношения к 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 своих операндов. Для демонстрации этого поведения можно использовать множество операторов.

ответил(а) 2011-06-13T17:25:00+04:00 8 лет, 8 месяцев назад
86

Это не sizeof с двумя аргументами. sizeof - это оператор, а не функция.


Считаем, что (0, arr) - выражение, использующее оператор запятой, и все остальное встает на свои места.

ответил(а) 2011-06-13T17:18:00+04:00 8 лет, 8 месяцев назад
69

sizeof не принимает два аргумента. Но это не функция,
поэтому (...) не ограничивают аргументы функции, они просто
необязательная часть синтаксиса и принудительная группировка. Когда вы пишете
sizeof(0, arr), аргументом sizeof является одиночное выражение 0,
arr
. Одно выражение с оператором запятой, которое оценивает
выражение слева от запятой, выбрасывает его значение (но не его
побочные эффекты), затем оценивает выражение справа от запятой,
и использует его значение как значение полного выражения.


Я не уверен в C, но это может быть разница между
. охват языков В С++ преобразование между массивами и указателями не происходит, если
необходимо; в C, если я правильно помню, стандарт говорит, что это
всегда происходит, за исключением определенных контекстов. Включая
оператора sizeof. В этом случае, поскольку оператор запятой не
имеют ограничения в отношении типов своих операндов,
преобразование массива в указатель не выполняется в С++. В C
оператор запятой не указан в исключениях, поэтому
преобразование массива в указатель имеет место. (В этом случае массив
является операндом оператора запятой, а не sizeof.)

ответил(а) 2011-06-13T17:44:00+04:00 8 лет, 8 месяцев назад
60

Лучший способ увидеть, что может происходить здесь, - это посмотреть на грамматику в стандарте. Если мы посмотрим на проект стандартного раздела 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] ) 

ответил(а) 2014-02-26T07:45:00+04:00 5 лет, 12 месяцев назад
49

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

ответил(а) 2011-06-27T13:18:00+04:00 8 лет, 7 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема