Распределение памяти одинаковых структур - PullRequest
2 голосов
/ 15 июля 2010

Итак, я учил моего друга указателям.При этом я заметил, что адреса двух одинаковых структур точно совпадают.

struct Foo
{
    int a;
};

struct Bar
{
    int b;
};

Что позволило мне сделать это:

Foo foo; foo.a = 100;
Bar bar; bar.b = 100;

Foo *pFoo = &foo;
Bar *pBar = &bar;

(pFoo+1)->a = 200;

Это переопределяет значениев bar.b и устанавливает его на 200.

Теперь я не подвергаю сомнению достоинства такой вещи - он, вероятно, никогда не увидит свет в реальной программе.Мне просто интересно, всегда ли ОС выделяет идентичные структуры подряд?При условии, что в данной области достаточно свободного места.

Ответы [ 6 ]

8 голосов
/ 15 июля 2010

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

6 голосов
/ 15 июля 2010

Операционная система не выделяет место в стеке для локальных переменных, компилятор делает. Компиляторы C ++ не гарантируют порядок размещения.

4 голосов
/ 15 июля 2010

Нет, это не гарантированно работает.

Прежде всего, нет гарантии на размещение в памяти не связанных между собой объектов. Единственный раз, когда объекты гарантированно размещаются в памяти непрерывно, это

  • если вы поместите их рядом друг с другом (например, вы вручную выделите некоторое количество байтов и разместите их один за другим) или
  • если они находятся в массиве (элементы массива всегда смежные

Итак, действует следующее:

int ints[2];
*(&ints[0] + 1) = 42;

Код в вопросе недействителен, потому что объекты foo и bar совершенно не связаны и могут быть размещены в любом месте памяти.

Существует несколько связанная с этим проблема, заключающаяся в том, что в структуре могут присутствовать и безымянные байты заполнения.

  • между членами структуры (чтобы элементы были правильно выровнены) и
  • в конце структуры (чтобы объекты этого типа структуры могли быть размещены непрерывно в массиве)

Это означает, что следующее недопустимо, потому что в конце Foo может быть безымянный отступ:

Foo foos[2];
*(&foos[0].a + 1) = 42;

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

4 голосов
/ 15 июля 2010

Нет - довольно часто компилятор / компоновщик размещает переменные в совершенно разных местах, которые не имеют никакого отношения к их расположению в исходных файлах.

Мне доставило особое удовольствие работать с кодом Cэто было переведено из сборки, которая сделала это предположение повсюду (в сборке, когда у вас есть 2 переменные рядом друг с другом в одном сегменте / разделе, это то, что вы получите в образе).

Это было не весело ...

Обратите внимание, что в вашем распоряжении могут быть инструменты (например, файлы конфигурации компоновщика или прагмы компилятора), которые могут дать вам некоторый контроль над размещением переменных в памяти.Но в этот момент вы определенно находитесь на «конкретной для реализации» территории, и вам все еще может потребоваться решить проблемы с выравниванием и еще много чего (хотя, если структуры имеют одинаковый размер, это, вероятно, не будет проблемой).

Переносимый способ иметь 2 структуры, смежные друг с другом, состоит в том, чтобы обернуть их в другую структуру (опять же, могут быть проблемы с арифметикой и псевдонимами указателей, хотя).

1 голос
/ 15 июля 2010

Это происходит не только со структурами.Отдельные переменные обычно являются смежными, но, как все говорили, это не гарантировано (действительно, в моем окне порядок инвертирован для следующего примера)

int a,b;
int *pa=&a;
int *pb=&b;
a=1;
b=2;
*(pa)=3;
*(pb+1)=4;
printf("a value: %i \tb value: %i\n", *pa, *pb);

Результат равен


a value: 4  b value: 2
1 голос
/ 15 июля 2010

Я помню, как сталкивался с ситуацией, когда использовалась вся программа оптимизации на gcc, когда она полностью переупорядочивала все глобальные переменные как часть процесса оптимизации. Тем не менее, нет такой гарантии для такого рода макетов для отдельных переменных в C ++.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...