Инициализация структуры до 0

117

Если у меня есть такая структура:

typedef struct
{
    unsigned char c1;
    unsigned char c2;
} myStruct;

Каким будет самый простой способ инициализировать эту структуру значением 0? Достаточно ли следующего?

myStruct _m1 = {0};

или мне нужно явно инициализировать каждого члена до 0?

myStruct _m2 = {0,0};
Даан Тиммер
источник

Ответы:

143

Первый самый простой ( требует меньше ввода ), и он гарантированно работает, все члены будут установлены на 0[Ref 1] .
Второй более читабельный.

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

[Ссылка 1] Ссылка C99 Стандарт 6.7.8.21:

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

Хорошее чтение:
C и C ++: частичная инициализация автоматической структуры

Алок Сохранить
источник
9
Кроме того, я использую, = {};однако я не уверен, действительно ли это.
Уильям Энтрикен,
15
@FullDecent пустые скобки для инициализации - это расширение GNU.
a3f
2
@ alias65536 Вопрос помечен как C, а не C ++.
a3f
3
Я получил сообщение об ошибке: «Отсутствуют фигурные скобки вокруг инициализатора [-Werror = missing-braces]», вероятно, из-за массива элементов: /
DrumM
3
@ Эдения. Я не согласен. Я уже знаю, что foo = {0}значит. Если бы я видел foo = ZERO_FULL, мне бы пришлось искать определение ZERO_FULL с помощью grep.
Эндрю Бейнбридж
32

Если данные являются статической или глобальной переменной, по умолчанию они заполняются нулями, поэтому просто объявите их. myStruct _m;

Если данные являются локальной переменной или зоной, выделенной кучей, очистите их, memsetнапример:

memset(&m, 0, sizeof(myStruct));

Текущие компиляторы (например, последние версии gcc) достаточно хорошо оптимизируют это на практике. Это работает, только если все нулевые значения (включая нулевые указатели и ноль с плавающей запятой) представлены как все нулевые биты, что верно для всех платформ, о которых я знаю (но C стандарт разрешает реализации, где это ложно; я не знаю такой реализации) .

Возможно, вы могли бы написать код myStruct m = {};или myStruct m = {0};(даже если первый член myStructне является скаляром).

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

Василий Старынкевич
источник
7
Нет никакой гарантии, что установка для всех байтов структуры значения 0будет эквивалентна инициализации всех членов структуры с помощью 0. На многих платформах это будет так, но не всегда.
Sander De Dycker,
1
Можешь привести пример, Сандер? Искреннее любопытство. (Очевидно, что не всегда верно, не обязательно означает, что есть легко объяснимое исключение, но если оно есть ...)
Стивен Фишер,
2
Стандарт C позволяет представлять нулевой указатель (или нулевое число с плавающей запятой) в памяти чем-то другим, кроме всех нулевых битов. Очень немногие и странные реализации делают это (я не могу назвать ни одной).
Василий Старынкевич
-1, вы можете найти инициализацию, о которой спрашивает OP, некрасивой, но это именно то, что предусмотрено стандартом и может быть легко оптимизировано всеми компиляторами. Тогда форма {}недействительна для C, а доступна только в C ++.
Jens Gustedt
8
@ Стивен: Я могу думать только о малоизвестных и / или старых платформах. В FAQ по C есть список платформ, на которых NULLуказатель не был полностью битовым0 : c-faq.com/null/machexamp.html . Кроме того, есть вероятность, что платформа не использует IEEE 754 для представления значений с плавающей запятой, а использует какое-то другое представление, которое не имеет полностью 0битового 0.0значения, но, по общему признанию, я не знаю такой платформы.
Сандер Де Дайкер,
19

См. §6.7.9 Инициализация:

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

Итак, да, они оба работают. Обратите внимание, что в C99 также может использоваться новый способ инициализации, называемый назначенной инициализацией:

myStruct _m1 = {.c2 = 0, .c1 = 1};
dirkgently
источник
В частности, это уже C89: open-std.org/JTC1/SC22/WG14/www/docs/n1124.pdf#page=139 (важно для конкретных целей обработки сигналов)
Тобиас