«C» sizeof с типом или переменной - PullRequest
21 голосов
/ 17 декабря 2008

Недавно видел, как кто-то порекомендовал другому пользователю использовать sizeof вместо 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 ]

46 голосов
/ 17 декабря 2008

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

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

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

6 голосов
/ 17 декабря 2008

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

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

4 голосов
/ 22 декабря 2009

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

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, чтобы успокоить мой разум.

3 голосов
/ 17 декабря 2008

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

2 голосов
/ 19 декабря 2008

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

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

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

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

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

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

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

0 голосов
/ 17 декабря 2008

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

...