Расположение памяти массива

#arrays #memory #layout

#массивы #память #расположение

Вопрос:

После некоторой игры с различными типами массивов я определил, что для каждого элемента требуется 2 бита «заполнения». Например, если тип данных массива — .int(32 бита или 2 ^ 5), то для каждого элемента массива выделено в общей сложности 4 ячейки памяти (всего 2 ^ 7 бит). Другой пример: если тип данных .short (16 бит или 2 ^ 4), то каждый элемент массива содержит 64 бита (2 ^ 6).

Вот пример.

 .data
IntArray:
.int 10, 20, 30, 40, 50

(gdb) info variables
0x080490a4 IntArray

(gdb) x/1wt 0x080490a4
0x80490a4 : 00000000000000000000000000001010
(gdb) x/1wt 0x080490a5
0x80490a5 : 00010100000000000000000000000000
(gdb) x/1wt 0x080490a6
0x80490a6 : 00000000000101000000000000000000
(gdb) x/1wt 0x080490a7
0x80490a7 : 00000000000000000001010000000000
(gdb) x/1wt 0x080490a8
0x80490a8 : 00000000000000000000000000010100
  

Очевидно, что ячейка памяти 0x080490a4 содержит первый элемент массива (значение 10). Также очевидно, что ячейка памяти 0x080490a8 содержит второй элемент массива.

Мой вопрос касается содержимого 0x080490a5 , 0x080490a6 0x080490a7 . Каково значение этих ячеек памяти? Я упускаю из виду некоторые подробности о том, как работают массивы?

Комментарии:

1. Я был немного сбит с толку, но я просто хочу убедиться, что мы находимся на одной странице. Что вы подразумеваете под «2 битами «заполнения»»?

Ответ №1:

Размер каждого элемента массива не имеет ничего общего с количеством элементов в массиве. Она определяется только типом данных, которые хранятся в массиве. Если у вас есть an int[] , каждый элемент массива будет точно такого же размера, как an int . Размер int , с другой стороны, зависит от операционной системы и аппаратной платформы ABI, и в большинстве компьютерных систем, с которыми вы, вероятно, столкнетесь, он будет составлять 32 бита.

Чтобы вычислить размер каждого массива, вы должны умножить размер каждого элемента на количество элементов. Итак, для вашего примера int a[4] :

 size = sizeof(int) * 4 = 32 * 4 bits = 2 ^ 5 * 2 ^ 2 bits = 2 ^ 7 bits = 128 bits = 16 bytes
  

Это размер массива, а не каждого отдельного элемента.

Теперь команда x/1wt GDB отображает содержимое слова, которое хранится в предоставленном адресе. Пока адрес указывает на элемент массива, вы должны видеть его содержимое. Но когда вы переходите от одного элемента к следующему, вам нужно добавить количество байтов в каждом элементе вместо сдвига местоположения на один байт. В вашем случае:

  • 0x080490a4 является адресом первого элемента массива
  • 0x080490a8 является адресом второго элемента массива
  • 0x080490a5 Все адреса, 0x080490a6 и 0x080490a7 не выровнены (т. Е. они не кратны размеру слова), которые указывают на 4 байта каждый. Из этих 4 байтов часть принадлежит первому, а часть — второму элементу.

Из-за того факта, что процессоры x86 имеют порядковый номер, где первым идет младший значащий байт (LSB), расположение в физической памяти этих двух элементов будет следующим:

 0x080490a4: 00001010 00000000 00000000 00000000
0x080490a8: 00010100 00000000 00000000 00000000
  

Увеличивая адрес на один байт, ваш компьютер видит:

 0x080490a5: 00000000 00000000 00000000 00010100
0x080490a9: 00000000 00000000 00000000 ...
  

Т.е. значение, хранящееся в 0x080490a5 , имеет:

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

  • в качестве наиболее значимого байта используется первый байт (т.е. наименее значимый) второго элемента массива

И поскольку x86 имеет порядковый номер, а GDB переупорядочивает отображаемые байты, так что MSB отображается первым, вы получаете:

 0x80490a5: 00010100 00000000 00000000 00000000
  

Комментарии:

1. Спасибо за объяснение. Я думаю, что большая часть моей путаницы возникла из-за того, что я думал, что каждый 32-битный адрес памяти указывал на 32-битный, но теперь я понимаю, что он указывает только на 8 бит. Все гораздо яснее — перейдем к более подробному изучению ассемблера.