Разрешено ли превышать один элемент структуры для просмотра другого?
Учитывая следующий придуманный пример кода:
struct abc
{
int x[5];
int y[5];
};
void main()
{
struct abc test;
test.y[0] = 10;
printf("%n", test.x[5]);
}
Выход программы 10.
Хотя это не лучшая практика программирования, это работает. Однако это артефакт компилятора и платформы, или это юридический код? (то есть определяется стандартом C?)
Даже если результат не гарантированно равен 10, есть ли когда-нибудь случай, когда это будет "незаконно" (т.е. запись в память, которой я не "владею")?
4 ответа
РЕДАКТИРОВАТЬ: Как указано другими, это не является законным, так как это приводит к неопределенному поведению. Я удалил это предложение из своего ответа.
Это может привести к неопределенному поведению. Вы выделили кусок памяти длиной 10 дюймов в struct abc, поэтому индексирование по 5-му (6-му) элементу приведет вас к y[0], как вы отметили в ЭТОМ конкретном случае.
Проблемы могут возникнуть, когда компилятор C упакует структуру так, как вы этого не ожидаете. Это называется упаковкой данных или выравниванием битов. Когда компьютер хочет получить доступ к памяти из вашей структуры данных, он попытается сделать это единообразно для всей структуры. Давайте использовать пример:
struct abc {
int a;
char b;
int c;
};
Какой размер этой структуры вы ожидаете? Значение int - 32 бита, а char - 8 бит, поэтому общий размер должен быть 32 + 8 + 32 = 72 бита. Однако вы обнаружите, что во многих системах эта структура на самом деле имеет размер 96 бит. Причина в том, что в конце char b упаковывается бит с дополнительными 24 битами для поддержания стандартного смещения между переменными.
Это может быть очень запутанным, когда вы объявляете структуру в двух разных местах, и одно становится немного упакованным, а другое - из-за опций времени компиляции или конфигурации.
Посмотрите упаковку битов и выравнивание данных или выравнивание битов для получения дополнительной информации.
Нет, это не законно и не гарантировано для работы. Компилятор может добавить отступы в структуру, чтобы помочь в выравнивании, в зависимости от архитектуры и т. Д.
Изменить: Подвести итог некоторых вещей в этих комментариях и уточнить...
Я действительно полагаю, что вы "владеете" памятью там, поскольку, как указывает edA-qa mort-ora-y, memcpy() из struct нуждается / будет работать. Где это конкретно гарантировано, хотя, я не уверен.
При этом неопределенного поведения следует избегать любой ценой. То, что делает программа с неопределенным поведением, может измениться между двумя отдельными запусками одного и того же кода с интервалом в пять секунд. Это может вызвать легкое повреждение памяти в вашей программе, segfault или просто нормально работать, но нет никаких причин когда-либо использовать код, основанный на неопределенном поведении.
Это неопределенное поведение - вам (не) в этом случае повезло. Более того (помимо упомянутой проблемы с заполнением), существует проблема с удобством сопровождения - она невероятно хрупкая - что, если кто-то вставит что-то другое между ними. Я уверен, что это надуманный пример, но рекомендация - не делай этого.
Технически поведение не определено.
Хотя это не лучшая практика программирования, это работает.
Неопределенное поведение означает, что может произойти все, что вы ожидаете. Это может привести к сбою в других реализациях.