Разрешено ли превышать один элемент структуры для просмотра другого? - PullRequest
8 голосов
/ 13 декабря 2011

С учетом следующего придуманного примера кода:

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 ]

12 голосов
/ 13 декабря 2011

Нет, это не законно и не гарантировано для работы. Компилятор может добавить отступы в структуру, чтобы помочь в выравнивании, в зависимости от архитектуры и т. Д.

Редактировать: Чтобы подвести итог некоторых вещей в этих комментариях и уточнить ...

Я верю, что вы «владеете» там памятью, поскольку, как указывает edA-qa mort-ora-y, memcpy () из struct нуждается / будет работать. Хотя, где это конкретно гарантировано, я не уверен.

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

5 голосов
/ 13 декабря 2011

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

4 голосов
/ 13 декабря 2011

РЕДАКТИРОВАТЬ: Как указано другими, это не является законным, так как это приводит к неопределенному поведению. Я удалил это предложение из своего ответа.

Это может привести к неопределенному поведению. Вы выделили кусок памяти длиной 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 битами для поддержания стандартного смещения между переменными.

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

Для получения дополнительной информации посмотрите упаковку битов и выравнивание данных или выравнивание битов.

3 голосов
/ 13 декабря 2011

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

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

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

...