"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);
На мой взгляд, первый сет это просто вопрос стиля. Но во второй паре строк лишнюю секунду * можно легко спутать с умножением.
7 ответов
Если тип переменной изменяется, sizeof не требует изменения, если переменная является аргументом, а не типом.
Что касается комментария @ icepack: возможность или вероятность изменения типа в зависимости от имени переменной не является проблемой. Представьте, что имя переменной используется в качестве аргумента для sizeof, а затем изменено. В лучшем случае операция refactor-rename изменяет все вхождения, и ошибки не возникает. В худшем случае пропускается экземпляр sizeof, и компилятор жалуется, и вы исправляете это. Если тип изменился, вы сделали, нет возможности ошибок в выражениях sizeof.
Теперь представьте, что тип является аргументом для sizeof. Если тип переменной изменяется, нет никакого другого средства, кроме проверки, чтобы найти все sizeof, относящиеся к этой переменной. Вы можете искать, но вы получите хиты для всех не связанных с использованием sizeof того же типа. Если один из них пропущен, у вас возникнет проблема во время выполнения из-за несоответствия размера, что гораздо сложнее найти.
В дополнение к тому, что говорит Стив, позвольте мне добавить, что sizeof не оценивает его операнд. Таким образом, вы можете сделать что-нибудь в этом. Вы можете не только использовать еще не инициализированные переменные, но и разыменовать нулевой указатель, вызывать функции, которые не определены, а только объявлены, и выполнять любые другие операции. Я призываю вас всегда использовать версию выражения по причинам, которые сильно объяснил Стив.
Также учтите, что иногда имена типов действительно длинные и нечитаемые, просто подумайте об указателях на функции (особенно в C++). Вместо того чтобы писать sizeof(my_long_type<weird, stuff>)
ты просто делаешь sizeof t
,
Вы можете увидеть небольшую разницу между этими:
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
успокоить мой разум.
Линии f и ff определенно хуже, чем g и gg. sizeof f
размер указателя, так как f является точкой. Чтобы сделать их эквивалентными, вам нужно написать sizeof *f
(или, для лучшей разборчивости, sizeof(*f)
).
Я склонен использовать sizeof(type)
в распределении памяти, но неизменно sizeof(variable)
при использовании локальной или глобальной переменной. Тем не менее, есть разумный совет использовать имя переменной все время.
У меня также была долгая дискуссия (иногда довольно оживленная, и длилась она в течение нескольких дней - мы перестали соглашаться расходиться по этому вопросу) о том, можно ли ее использовать sizeof(variable)
или это должно быть sizeof variable
; то есть имеет ли значение, заключают ли скобки аргумент в sizeof
, Я никогда не сталкивался с компилятором sizeof(variable)
поэтому я выбираю единообразие и всегда использую скобки с sizeof
, Мой коллега был также непреклонен, что круглые скобки не должны использоваться с переменными; что каким-то образом есть / было ценное различие между обозначениями с круглыми скобками и без них. Меня не убедили - я не ожидаю, что меня убедят.
С другой стороны, несколько других моментов sizeof
:
- Если вы используете C99 и VLA - массивы переменной длины - тогда
sizeof(vla)
не является константой времени компиляции. Осторожно! - Препроцессор C не понимает
sizeof
что неприятно, но логично.
Бизнес логика определяет ваш выбор.
Если ваш код ссылается на определенную переменную и без этой переменной ваш код не имеет смысла - выберите
sizeof(var)
Если ваш код имеет дело с набором переменных определенного типа - выберите
sizeof(type)
, Обычно вам это нужно, если у вас естьtypedef
который определяет много переменных, которые вы обрабатываете по-разному в зависимости от их типа (например, сериализация). Вы можете не знать, какая из этих переменных останется в будущих версиях кода, поэтому выбор типа в качестве аргумента является логически правильным. Даже смена такогоtypedef
не повлияет на вашsizeof
линия.
Взятие размера переменной может иметь неожиданные результаты. Когда переменная является массивом, sizeof(массив) будет возвращать размер массива, а не размер отдельного элемента или размер указателя. Взятие размера указателя вернет размер указателя. Но поскольку массивы обычно представляются в виде указателей при передаче, все может запутаться.