Memset() или инициализацию значения, чтобы обнулить структуру? - программирование
Подтвердить что ты не робот

Memset() или инициализацию значения, чтобы обнулить структуру?

В программировании API Win32 типично использовать C struct с несколькими полями. Обычно только пара из них имеет значимые ценности, и все остальные должны быть обнулены. Это может быть достигнуто одним из двух способов:

STRUCT theStruct;
memset( &theStruct, 0, sizeof( STRUCT ) );

или

STRUCT theStruct = {};

Второй вариант выглядит более чистым - он однострочный, он не имеет никаких параметров, которые могут быть омрачены и привести к появлению ошибки.

Есть ли у него недостатки по сравнению с первым вариантом? Какой вариант использовать и почему?

4b9b3361

Ответ 1

Эти две конструкции очень разные по своему значению. Первая использует функцию memset, которая предназначена для установки буфера памяти на определенное значение. Второй - для инициализации объекта. Позвольте мне объяснить это с помощью кода:

Предположим, что у вас есть структура, в которой есть только члены типов POD

struct POD_OnlyStruct
{
    int a;
    char b;
};

POD_OnlyStruct t = {};  // OK

POD_OnlyStruct t;
memset(&t, 0, sizeof t);  // OK as well

В этом случае запись POD_OnlyStruct t = {} или POD_OnlyStruct t; memset(&t, 0, sizeof t) не имеет большого значения, так как единственное различие, которое мы имеем здесь, это байты выравнивания, устанавливаемые на нулевое значение в случае использования memset. Поскольку у вас нет доступа к этим байтам, нет никакой разницы.

С другой стороны, поскольку вы отметили свой вопрос как С++, попробуйте другой пример, с типами участников, отличными от POD:

struct TestStruct
{
    int a;
    std::string b;
};

TestStruct t = {};  // OK

{
    TestStruct t1;
    memset(&t1, 0, sizeof t1);  // ruins member 'b' of our struct
}  // Application crashes here

В этом случае использование выражения типа TestStruct t = {} является хорошим, и использование memset на нем приведет к сбою. Здесь, что происходит, если вы используете memset - создается объект типа TestStruct, создавая таким образом объект типа std::string, поскольку он является членом нашей структуры. Затем memset задает память, в которой объект b находился на определенном значении, например, ноль. Теперь, как только наш объект TestStruct выходит из сферы действия, он будет уничтожен, и когда очередь придет к нему, член std::string b вы увидите сбой, так как все внутренние структуры этого объекта были разрушены memset.

Итак, реальность такова, что эти вещи очень разные, и хотя в некоторых случаях вам иногда требуется memset целая структура для нулей, всегда важно убедиться, что вы понимаете, что вы делаете, и не делаете как и в нашем втором примере.

Мое голосование - используйте memset для объектов, только если это необходимо, и используйте инициализацию по умолчанию x = {} во всех остальных случаях.

Ответ 2

В зависимости от членов структуры эти два варианта не обязательно эквивалентны. memset установит структуру на все биты-ноль, тогда как инициализация значений будет инициализировать все члены до нулевого значения. Стандарт C гарантирует, что они будут одинаковыми только для интегральных типов, а не для значений с плавающей запятой или указателей.

Кроме того, некоторые API требуют, чтобы структура действительно была установлена ​​на все биты-ноль. Например, API-интерфейс сокетов Berkeley использует структуры полиморфно, и там важно действительно установить всю структуру в нуль, а не только значения, которые очевидны. В документации API должно быть указано, действительно ли структура должна быть полностью-бит-ноль, но она может быть недостаточной.

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

Ответ 3

Если ваша структура содержит такие вещи, как:

int a;
char b;
int c;

Затем байты заполнения будут вставлены между "b" и "c". memset() будет нулевым, другой путь не будет, поэтому будет 3 байта мусора (если ваши ints 32 бита). Если вы намерены использовать вашу структуру для чтения/записи из файла, это может быть важно.

Ответ 4

Я бы использовал инициализацию значения, потому что он выглядит чистым и меньше подвержен ошибкам, как вы упомянули. Я не вижу недостатка в этом.

Вы можете положиться на memset, чтобы обнулить структуру после ее использования.

Ответ 5

не то, что он общий, но, я думаю, второй способ также имеет преимущество инициализации поплавок до нуля. Если делать memset, конечно, не

Ответ 6

В некоторых компиляторах STRUCT theStruct = {}; переводится в memset( &theStruct, 0, sizeof( STRUCT ) ); в исполняемый файл. Некоторые функции C уже связаны с настройкой среды выполнения, поэтому у компилятора эти функции библиотеки, такие как memset/memcpy, доступны для использования.

Ответ 7

Инициализация значения, поскольку это можно сделать во время компиляции.
Также он правильно 0 инициализирует все типы POD.

Функция memset() выполняется во время выполнения.
Также использование memset() является подозрительным, если структура не POD.
Не правильно инициализирует (до нуля) типы non int.

Ответ 8

Если есть много элементов указателя, и вы, вероятно, добавите больше в будущем, это может помочь использовать memset. В сочетании с соответствующими вызовами assert(struct->member) вы можете избежать случайных сбоев, пытаясь почтить плохой указатель, который вы забыли инициализировать. Но если вы не так забываетесь, как я, то инициализация членов, вероятно, самая лучшая!

Однако, если ваша структура используется как часть общедоступного API, вы должны получить код клиента для использования memset в качестве требования. Это помогает с будущей проверкой, потому что вы можете добавлять новых членов, а клиентский код автоматически отменяет их в вызове memset, вместо того, чтобы оставлять их в (возможно опасном) неинициализированном состоянии. Это то, что вы делаете при работе с структурами сокетов, например.