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

StackOverflow https://stackoverflow.com/questions/177393

  •  05-07-2019
  •  | 
  •  

Вопрос

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

   *(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 не обязательно должно означать «все биты ноль», это может быть что угодно для процессора.

Это было полезно?

Решение

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 / с-1.html

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

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

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

Другие советы

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

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

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

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

Частная функция инициализации не является уродливым, а скорее хорошим 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 структуры.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top