Каков правильный способ инициализации очень большой структуры?

В нашем коде у нас было что-то вроде этого:

   *(controller->bigstruct) = ( struct bigstruct ){ 0 };

Это работало отлично, а затем мы обновили версии GCC и внезапно начали видеть переполнение стека. Глядя на сборку, старый код GCC (2.x) в основном делал это:

memset(controller->bigstruct, 0, sizeof(struct bigstruct));

Новый GCC (3.4.x) делал это

   struct bigstruct temp = { 0 };
   controller->bigstruct = temp;

После просмотра спецификации C99 я мог понять, почему; C99 требует, чтобы в стеке существовали анонимные структуры. Это хорошая концепция, но эта структура была 4 мегабайта большой и только когда-либо предназначалась для существования в куче!

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

Что такое "правильный" или, по крайней мере, лучший способ инициализации такой большой структуры?

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

'memset' установит память на нулевой бит-шаблон, что не обязательно одно и то же. Представьте себе систему, которая не использует числа с плавающей запятой IEEE. Необычно, но поддерживается C. Представление 0.0 не должно означать "all-bits zero", оно может быть удобным для процессора.

Ответ 1

memset - это путь. У вас мало альтернатив.

Сделайте что-то вроде:

#define InitStruct(var, type) type var; memset(&var, 0, sizeof(type))

Итак, вам нужно только:

InitStruct(st, BigStruct);

И затем используйте st как обычно...

Я не понимаю, как "0" не является допустимым типом "0" для структуры. Единственный способ "массовой инициализации" структуры - установить всю свою память на значение; в противном случае вам придется сделать дополнительную логику, чтобы сказать ей использовать конкретный бит-шаблон для каждого члена. Лучшим "универсальным" битовым шаблоном для использования является 0.

Кроме того - это та же логика, которую вы использовали при выполнении

*(controller->bigstruct) = *( struct bigstruct ){ 0 };

Поэтому я не понимаю ваше нежелание использовать его:)

Первый комментарий к этому сообщению заставил меня провести некоторое исследование, прежде чем я позвонил ему и идиотом, и я нашел это:

http://www.lysator.liu.se/c/c-faq/c-1.html

Очень интересно; если бы я мог проголосовать за комментарий, я бы:)

Это означает, что ваш единственный вариант, если вы хотите нацеливать архаические архитектуры с ненулевыми значениями, отличными от 0, по-прежнему выполняет ручную инициализацию для определенных членов.

Спасибо Томасу Падрон-Маккарти! Сегодня я узнал что-то новое:)

Ответ 2

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

Тем не менее, если GCC использовал memset, и это было достаточно хорошо, я бы предположил, что сейчас это достаточно хорошо.

Ответ 3

Как говорили другие, memset - это путь. Однако не используйте memset для объектов С++, особенно для виртуальных методов. sizeof( foo ) будет включать таблицу указателей виртуальных функций, и выполнение memset на этом вызовет серьезное горе.

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

Ответ 4

Частная функция инициализации не является уродливым, а хорошим способом OO для инициализации объектов (структур). Я предполагаю, что ваша структура не 4MB указателей, поэтому я бы предположил, что решение должно быть таким:

void init_big_struct(struct bigstruct *s)  
{  
    memset(s, 0, sizeof(struct bigstruct));  
    s->some_pointer = NULL; // Multiply this as needed  
}

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

Ответ 5

hmm - прежде всего выполнение функции init и установка каждого элемента явно ЯВЛЯЕТСЯ ПРАВИЛЬНЫМ - это, как работают конструкторы в языках OO.

и второй - кто-нибудь знает аппаратное обеспечение, которое реализует номера с плавающей точкой без IEEE? - возможно, Commodore 64 или somethig; -)