Подтвердить что ты не робот

"C" sizeof с типом или переменной

Недавно увидел, что кто-то благодарит другого пользователя за использование sizeof var вместо sizeof (type). Я всегда думал, что это всего лишь выбор стиля. Есть ли существенная разница? В качестве примера линии с f и ff считались лучшими, чем линии с g и gg:

 typedef struct _foo {} foo;

 foo *f = malloc(count * sizeof f);
 foo *g = malloc(sizeof(foo) * count);

 foo **ff = malloc(count * sizeof *ff);
 foo **gg = malloc(sizeof(foo*) * count);

По моему мнению, первый набор - это всего лишь вопрос стиля. Но во второй паре строк дополнительная секунда * легко сбивается с толку для умножения.

4b9b3361

Ответ 1

Если тип переменной изменен, sizeof не требует изменения, если переменная является аргументом, а не типом.

Что касается комментария @icepack: возможность или вероятность изменения имени типа и переменной не является проблемой. Представьте, что имя переменной используется как аргумент sizeof, а затем изменено. В лучшем случае операция refactor-rename изменяет все вхождения и не вводится ошибка. В худшем случае экземпляр sizeof пропущен, и компилятор жалуется, и вы его исправляете. Если тип изменен, вы сделали, нет возможности ошибок в операторах sizeof.

Теперь представьте, что type является аргументом sizeof. Если тип переменной изменен, нет никаких средств, кроме осмотра, чтобы найти все значения sizeof, относящиеся к этой переменной. Вы можете искать, но вы получите хиты для всех несвязанных видов использования sizeof того же типа. Если вы пропустили, у вас будет проблема времени выполнения из-за несоответствия размера, что гораздо труднее найти.

Ответ 2

В дополнение к тому, что говорит Стив, позвольте мне добавить, что sizeof не оценивает его операнд. Поэтому вы можете делать что-либо в этом. Не только вы можете использовать не инициализированные переменные, но вы можете разыменовать нулевой указатель, функции вызова не определены, а только объявлены и выполняются любые другие вещи. Я призываю вас всегда использовать версию выражения по причинам, которые Стив объяснил очень.

Также подумайте, что иногда имена типов действительно длинные и нечитаемые, просто подумайте о указателях на функции (особенно на С++). Вместо записи sizeof(my_long_type<weird, stuff>) вы просто выполняете sizeof t.

Ответ 3

Вы можете видеть небольшую разницу между ними:

foo **ff = malloc(count * sizeof *ff);
foo **gg = malloc(sizeof(foo*) * count);

.. но что, если распределение не находится рядом с объявлением? Если я столкнулся с такой строкой, как:

ff = realloc(ff, count * sizeof *ff);

то я уверен, что строка правильная, даже не помню тип ff. Однако, если я вижу это:

ff = realloc(ff, count * sizeof(foo *));

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

Ответ 4

Линии f и ff определенно хуже, чем g и gg. sizeof f - размер указателя, так как f является точкой. Чтобы сделать их эквивалентными, вам нужно написать sizeof *f (или, для большей удобочитаемости, sizeof(*f)).

Ответ 5

Я использую sizeof(type) в распределении памяти, но всегда sizeof(variable) при использовании локальной или глобальной переменной. Тем не менее в совете есть мудрость использовать имя переменной все время.

У меня также была длинная дискуссия (довольно оживленная время от времени, и она продолжалась в течение нескольких дней - мы закончили соглашаться по этому поводу) о том, можно ли использовать sizeof(variable) или она должна быть sizeof variable; то есть имеет значение, заключают ли круглые скобки аргумент sizeof. Я никогда не сталкивался с компилятором, который witters о sizeof(variable), поэтому я выбираю единообразие и всегда использую круглые скобки с sizeof. Мой коллега был в равной степени непреклонным, что круглые скобки не должны использоваться с переменными; что каким-то образом существует/было ценное различие между обозначениями с круглыми скобками и без них. Меня не уговорили - я не ожидаю, что вас уговорят.

На совершенно другом уровне, пару других точек о sizeof:

  • Если вы используете C99 и VLA - массивы переменной длины, то sizeof(vla) не является константой времени компиляции. Осторожно!
  • Препроцессор C не понимает sizeof, который является неприятным, но логичным.

Ответ 6

Взятие sizeof переменной может иметь неожиданные результаты. Когда переменная является массивом, sizeof (array) возвращает размер массива, а не размер отдельного элемента или размер указателя. Принимая размер указателя, он вернет размер указателя. Но поскольку массивы обычно отображаются в виде указателей, когда их пропускают, вещи могут запутаться.

Ответ 7

Бизнес-логика определяет ваш выбор.

  • Если ваш код относится к определенной переменной и без этой переменной ваш код не имеет смысла - выберите sizeof(var)

  • Если код закодирован с набором переменных с определенным типом - выберите sizeof(type). Обычно вам это нужно, если у вас есть typedef, который определяет многие переменные, которые вы обрабатываете по-разному в зависимости от их типа (например, сериализации). Возможно, вы не знаете, какая из этих переменных останется в будущих версиях кода, поэтому выбор типа в качестве аргумента логически правильный. Даже изменение такого typedef не повлияет на вашу строку sizeof.