Каков правильный способ инициализации очень большой структуры?
В нашем коде у нас было что-то вроде этого:
*(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; -)