Разрешено ли превышать один элемент структуры для просмотра другого?

Учитывая следующий придуманный пример кода:

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 или просто нормально работать, но нет никаких причин когда-либо использовать код, основанный на неопределенном поведении.

Это неопределенное поведение - вам (не) в этом случае повезло. Более того (помимо упомянутой проблемы с заполнением), существует проблема с удобством сопровождения - она ​​невероятно хрупкая - что, если кто-то вставит что-то другое между ними. Я уверен, что это надуманный пример, но рекомендация - не делай этого.

Технически поведение не определено.

Хотя это не лучшая практика программирования, это работает.

Неопределенное поведение означает, что может произойти все, что вы ожидаете. Это может привести к сбою в других реализациях.

Другие вопросы по тегам