Учитывая
struct node
{
int a;
struct node * next;
};
Чтобы добавить новую структуру,
struct node *p = malloc(sizeof(*p));
безопаснее, чем
struct node *p = malloc(sizeof(struct node));
Почему? Я думал, что они одинаковые.
Учитывая
struct node
{
int a;
struct node * next;
};
Чтобы добавить новую структуру,
struct node *p = malloc(sizeof(*p));
безопаснее, чем
struct node *p = malloc(sizeof(struct node));
Почему? Я думал, что они одинаковые.
Это безопаснее, потому что вам не нужно упоминать имя типа дважды и не нужно создавать правильное написание для "разыменованной" версии этого типа. Например, вам не нужно "подсчитывать звезды" в
int *****p = malloc(100 * sizeof *p);
Сравните это с типом sizeof
в
int *****p = malloc(100 * sizeof(int ****));
где вы также убедитесь, что вы использовали правильное число *
под sizeof
.
Чтобы переключиться на другой тип, вам нужно изменить только одно место (объявление p
) вместо двух. И люди, у которых есть привычка бросать результат malloc
, должны изменить три места.
В более общем смысле, имеет смысл придерживаться следующего руководства: имена типов принадлежат декларациям и нигде больше. Фактические утверждения должны быть независимы от типа. Они должны избегать упоминания любых имен типов или использования любых других специфичных для конкретного типа функций как можно больше.
Последнее означает: избегайте ненужных бросков. Избегайте ненужного синтаксиса констант типа (например, 0.0
или 0L
, где достаточно простого 0
). Избегайте упоминания имен типов в sizeof
. И так далее.
Потому что если в какой-то более поздний момент времени p
делается ссылка на другой тип структуры, то ваш оператор выделения памяти с помощью malloc
не должен изменяться, он по-прежнему выделяет достаточно памяти, необходимой для нового типа. Он обеспечивает:
В общем, всегда хорошая практика не полагаться на конкретные типы, и первая форма просто делает это, она не жестко кодирует тип.
Это удобно, потому что вы можете преобразовать это:
struct node *p= malloc(sizeof(*p));
В это:
#define MALLOC(ptr) (ptr) = malloc(sizeof(*(ptr) ))
struct node *p;
MALLOC(p);
Или, для массива:
#define MALLOC_ARR(ptr, arrsize) \
(ptr) = malloc(sizeof(*(ptr) ) * arrsize)
struct node *p;
MALLOC_ARR(p, 20);
И почему это безопасно? Поскольку пользователь, который использует эти макросы, с меньшей вероятностью допустит ошибки, которые были обозначены AndreyT, так же, как в случае DIM()
, чтобы получить размер статического массива.
#define DIM(arr) ((sizeof(arr))/(sizeof(arr[0])))
Это также безопаснее, потому что пользователю не нужно согласовывать размер статического массива в нескольких местах. Задайте размер массива в одном месте, а затем просто используйте DIM()
, и все готово! Компилятор позаботится об этом для вас.
Это не влияет на безопасность напрямую, но можно утверждать, что это может помешать ошибке в будущих версиях. С другой стороны, легко забыть, что мало *
. Как сделать его типом, он, безусловно, чище.
typedef struct node
{
int a;
struct node * next;
} node_t;
Затем вы можете сделать это:
node_t *p = malloc(sizeof(node_t));