Как правильно инициализировать очень большую структуру? - PullRequest
22 голосов
/ 07 октября 2008

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

   *(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 мегабайта и предназначалась только для кучи!

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

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

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

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

Ответы [ 5 ]

21 голосов
/ 07 октября 2008

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

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

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

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

6 голосов
/ 07 октября 2008

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

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

5 голосов
/ 07 октября 2008

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

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

4 голосов
/ 07 октября 2008

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

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

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

0 голосов
/ 07 октября 2008

хмм - прежде всего создание функции инициализации и установка каждого члена явным образом - ПРАВДА - так работают конструкторы в ОО-языках.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...