memset () или инициализация значения для обнуления структуры?

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

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

или

STRUCT theStruct = {};

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

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

63
задан jww 12 August 2015 в 06:51
поделиться

8 ответов

Эти две конструкции очень различаются по своему значению. Первый использует функцию 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 . Поскольку у вас обычно нет доступа к этим байтам, для вас нет никакой разницы.

С другой стороны, поскольку вы пометили свой вопрос как C ++, давайте попробуем другой пример, с типами членов , отличными от 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 выходит за пределы области видимости, он будет уничтожен, и когда дойдет очередь до его member std :: string b , вы увидите сбой, так как все внутренние структуры этого объекта были разрушены memset .

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

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

86
ответ дан 24 November 2019 в 16:15
поделиться

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

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

.
7
ответ дан 24 November 2019 в 16:15
поделиться

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

.
5
ответ дан 24 November 2019 в 16:15
поделиться

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

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

.
2
ответ дан 24 November 2019 в 16:15
поделиться

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

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

.
-1
ответ дан 24 November 2019 в 16:15
поделиться
[

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

]. [

] Также, некоторые API требуют, чтобы структура действительно была установлена на all-bits-zero. Например, API сокета Berkeley использует структуры полиморфно, и там важно действительно установить всю структуру на ноль, а не только видимые значения. В документации API должно быть сказано, действительно ли структура должна быть all-bits-zero, но это может быть недостаточно.[

]. [

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

].
29
ответ дан 24 November 2019 в 16:15
поделиться

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

int a;
char b;
int c;

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

9
ответ дан 24 November 2019 в 16:15
поделиться

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

3
ответ дан 24 November 2019 в 16:15
поделиться