"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 что неприятно, но логично.

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

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

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

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

Другие вопросы по тегам