#c #struct
#c #структура
Вопрос:
Я беру на себя часть кода .. программирование на c в Linux. Я внес небольшое изменение в структуру
typedef struct {
unsigned int a1;
..
..
..
float f1;
unsigned int a2;
unsigned int a3;
unsigned int offending; // shifted this
} test;
Я переместил unsigned int, оскорбляющий перед float f1, вот так:
typedef struct {
unsigned int a1;
..
..
..
unsigned int offending;
float f1;
unsigned int a2;
unsigned int a3;
} test;
и происходит сбой кода… в чем может быть проблема?
Важен ли порядок элементов структуры c?
Комментарии:
1. Независимо от того, изменяет ли это расположение структуры в памяти, зависит от реализации. Если у вас есть другой фрагмент кода, который ищет, скажем, 64 бита в структуре для чего-то, теперь он получает данные, которых он не ожидает. Связано ли это с другим программным обеспечением, которое не было перекомпилировано? Или это автономно. Кроме того, в зависимости от реализации это может привести к изменению общего размера типа, если оно испортит выравнивание, которое использовал компилятор.
2. «в чем может быть проблема?» — проблема с вашим кодом или проблема, с которой вы столкнулись? На первый мы не можем ответить, поскольку не видим ничего, кроме структуры typedef . Последнее, вероятно, связано с тем, что вы изменили свой макет, не понимая, как он используется во всем вашем коде, и не смогли что-то учесть (например: двоичная структура, считанная с диска предыдущих сохраненных данных со старым макетом, сокет от клиента / сервера, скомпилированный со старой версией, не зная о новой версиии т.д.).
3. Согласен с комментариями выше. Если ваш make-файл не имеет надлежащих зависимостей, он может не выполнить перекомпиляцию файлов, зависящих от этой структуры.
4. Весь аварийный код должен быть включен в вопрос, иначе мы не знаем, что может быть причиной проблемы.
5. Важно понимать, что, хотя вы обычно не используете
struct offset
для доступа к элементам структуры, существует множество структур данных, которые это делают. Особенно в таких структурах, как связанные списки, которые используют типы void для общих реализаций. Там порядок элементов в структуре имеет решающее значение. Изменение порядка в этом случае легко увидеть, как это может привести к сбою.
Ответ №1:
В чем может быть проблема? Зависит от остальной части кода и от того, что еще вы сделали.
Нет, порядок элементов структуры не является внутренне важным. Это делается так, когда от этого зависит другой код.
Возможные причины (не исчерпывающие):
- Вы не перекомпилировали все, и в этой структуре или в каком-то ее аспекте есть внешняя связь.
- Перемещая элемент, вы изменили выравнивание других элементов и / или sizeof() структуры и не компенсировали это.
- Где-то есть литеральная константа или макрос с размером или смещением, которые зависят от этой структуры.
- Существует ошибочный код, который никогда раньше не давал сбоев, но теперь происходит из-за изменения расположения памяти.
- Структура используется где-то как часть другой структуры или объединения, и проблема связана с этим.
- Существует инициализация списка с использованием {}, которая больше не соответствует порядку элементов.
Вы действительно должны предоставить подробную информацию о том, как он выходит из строя. В противном случае это догадки. И, возможно, даже тогда.
редактировать: ht @Jens.
Комментарии:
1. Более поздний код использует
struct offset
для доступа к элементам структуры, которые теперь получаетunsigned int offending
вместоfloat f1
.2. @DavidC.Rankin: Разве я не использовал для этого «литеральную константу или макрос … смещение»? Какой другой случай вы имели в виду?
3. Ну, нет (по крайней мере, я изначально не привязывался к нему). Я думал об общей реализации связанного списка, которая использует адрес структуры смещение для доступа к элементу. Это не попало в постоянный или макроязык вашего третьего пункта, поскольку я изначально его прочитал. (перечитывая его, я вижу, что литеральной константой, как вы пишете, будет указанное смещение) Извините за шум.
Ответ №2:
Наиболее вероятной причиной сбоев при изменении компоновки данных является инициализация. Если в вашем коде есть старые инициализаторы, которые используют порядок объявления, внезапно поля получат другие значения, чем раньше. Поэтому современный C, начиная с C99, назначил инициализаторы, которые позволяют избежать этой проблемы:
test toto = { 32, ... , 42, }; // sensible to reordering
test tata = { .a1 = 32, ... , .offending = 42, }; // still the same