"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);
По моему мнению, первый набор - это всего лишь вопрос стиля. Но во второй паре строк дополнительная секунда * легко сбивается с толку для умножения.
Ответы
Ответ 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
.