1

Я только что сделал грубый расчет для максимального размера беззнакового 64-битного целого числа, которое:

18,446,744,073,709,551,615
q5 q4  t   b   m   t   h

Если посмотреть на технические характеристики оборудования AWS на их самых больших компьютерах, он получит до 3,904GB , что:

3,904,000,000,000,000,000 bytes
5 q4  t   b   m   t   h

Для меня это означает, что указатели хранятся как 64-битные целые числа. Я новичок в мышлении о памяти и указателях, но просто хотел уточнить это.

Я немного смущен, хотя все еще. Указатель - это "конструкция языка программирования". Технически, даже на 64-битной машине, если вы используете менее чем ~ 4 миллиарда целых чисел (максимальный размер 32-битного целого), то мне интересно, почему вы не можете просто указывать 32-битные указатели. Таким образом, указатели будут 32-битными, пока вы не исчерпаете пространство, тогда вы можете начать использовать 64-битные указатели. Тогда это даст вам немного больше места для большего количества объектов.

Все еще в замешательстве, хотя. Указатель содержит местоположение адреса в памяти. Там написано, что "адрес" 64-битный. Так что, если бы у нас были 32-битные указатели, указывающие на 32-битные фрагменты в 64-битной памяти, я не уверен, что это будет выглядеть или означать. Похоже, это означает, что вам придется делать смещения (хотя я не очень хорошо понимаю это).

Интересно, можно ли продемонстрировать в C, Assembly или JavaScript, как будет выглядеть хранение 32-разрядных указателей в 64-разрядном адресном пространстве. Если C обрабатывает это для вас автоматически, то как это делает Assembly.


Я хотел бы знать, как я мог бы использовать большую память, как описано выше, но хранить 32-разрядные указатели, пока не будет достигнут максимум, затем использовать 64-разрядные указатели, и не уверен, как это будет выглядеть точно. Я постараюсь нарисовать диаграмму, объясняющую, как я об этом думаю.

  | The bars and . are like a ruler and mark the bit positions.
  - Each row under a number (1, 2, 3, ...) means a memory address.
  ⬚ Means no data in memory address.
  ⬒ Means data of type 1 in memory address.
  ■ Means data of type 2 in memory address.
  ● Means a bit of integer pointer is plugged into memory address slot.
  ◌ Means no bit of integer pointer is plugged into memory address slot.
                                                                                                                                 |
                                                                 |                                                               |
                                 |                               |                               |                               |
                 |               |               |               |               |               |               |               |
         |       |       |       |       |       |       |       |       |       |       |       |       |       |       |       |
   . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |

1. Empty 64-bit memory.
   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌
   ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚
   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ...
   ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ⬚ ...
   ...
   ...

2. 64-bit memory filled with 32-bit pieces of data (type 1 ⬒, type 2 ■).
   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌
   ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ...
   ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ...
   ...
   ...

3. 64-bit memory filled with 64-bit pieces of data.
   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌
   ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ...
   ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ...
   ...
   ...

4. 64-bit memory filled with 4-bit pieces of data.
   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌
   ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒
   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ...
   ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ...
   ...
   ...

5. 64-bit memory filled with 32-bit pieces of data, with second 32-bits accessed by a 32-bit pointer.
   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●
   ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ 
   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ...
   ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ... 
   ...
   ...

6. 64-bit memory filled with 64-bit pieces of data, with second 64-bits accessed by a 64-bit pointer.
   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌
   ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■
   ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ...
   ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ...
   ...
   ...

7. 64-bit memory filled with 4-bit pieces of data, with second piece of data accessed by a pointer.
   ◌ ◌ ◌ ◌ ● ● ● ● ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌
   ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒
   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ...
   ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ⬒ ⬒ ...
   ...
   ...

8. 64-bit memory filled with 8-bit pieces of data, with second piece of data accessed by a pointer.
   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ● ● ● ● ● ● ● ● ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌
   ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ 
   ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ...
   ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ■ ■ ■ ■ ■ ■ ■ ■ ⬒ ⬒ ⬒ ⬒ ⬒ ⬒ ...
   ...
   ...

Я представляю, что целые числа - это ключи к замку (который является адресом памяти). Пустое отверстие для ключа выглядит как 64 in подряд в (1). Полное отверстие для ключа для 64-битного адреса выглядит как 64 ● в строке в (6). Если я дам 64-битному адресному пространству памяти 32-битный ключ, это будет выглядеть так (5). Таким образом, он не будет полностью заполнять отверстие для ключа длиной 64 бита (64 дюйма), он будет заполнять (в данном случае) вторую половину. И поэтому кажется, что это не соответствует адресу. Но я пытаюсь указать на 32-битные данные прямо во второй половине! Чтобы сопоставить адрес, кажется, вам нужно заполнить ключевые отверстия в полной 64-битной строке, как в (6). Мне интересно, не нарушено ли мое понимание, пожалуйста, дайте мне знать, где я.

В случае, если это неясно, первые цифры 1-4 на диаграмме показывают данные, которые лежат в памяти (где 1 - пустая память). Вторые цифры 5-8 показывают, что мы пытаемся получить доступ к данным с помощью указателя (● черные кружки в строке являются указателем / ключом к блокировке адреса памяти).

Наконец, у меня есть последний вопрос. Интересно, можете ли вы пойти дальше и хранить данные в еще меньших порциях. Например, хранение 4-битных данных, как в (7). Это просто демонстрирует, как работает система указателей и адресов, более подробно. Я не знаю, можно ли указать 4-битный указатель на 4-битный фрагмент памяти. Похоже, что из-за требований к выравниванию вы должны получать как минимум 8 бит за раз. Но это нормально. Я просто хочу убедиться, что есть или нет возможности использовать n-битный указатель для доступа к n-битным данным в 64-битном пространстве памяти.

И если так, то как бы это выглядело, либо в C, либо в Assembly, либо в JavaScript также будет работать.

Я хотел бы знать это, чтобы знать, как вы должны хранить данные в 64-битной памяти, и что вам разрешено делать с указателями, учитывая, что «адреса памяти являются 64-битными». То есть, если я могу сделать memory.get(a32BitPointer) и заставить его вернуть 32 бита данных из 32-битного выровненного слота памяти. (Или, что эквивалентно, 4, 8, 16 и т.д. Бит данных или указатель размера).

2 ответа2

3

А указатель указывает содержит абсолютный адрес.

Если вам нужно добавить значение перед использованием указателя, то у вас есть смещение, а не реальный указатель.

В C указатель void может быть указателем на функцию, например, через него можно вызвать функцию. Чтобы это работало, вам нужны все 64 бита, если процессор находится в 64-битном режиме.

Если ваш ЦП поддерживает 64 адресных строки (может физически иметь меньше), то он имеет адресное пространство 2 ^ 64, которое равно 0x1 0000 0000 0000 0000 - в диапазоне от 0x0000 0000 0000 0000 до 0xFFFF FFFF FFFF FFFF .

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

Смещения медленнее, потому что ЦП должен добавить, чтобы получить адрес, который вы хотите, хотя ЦП имеют собственные инструкции, которые делают это тоже.

Я не супер эксперт по ISA x86-64, но, вероятно, есть инструкции процессора, которые обрабатывают 32-битные значения как 64-битные значения, причем первые 32 бита предполагаются равными 0. Процессору все еще приходится "расширять" реальное значение до 64 бит.

В x86 и x86-64 вы, конечно, можете использовать 8, 16, 32 и 64-битные смещения (никакие инструкции CPU x86/x86 не работают только с 4-битными значениями)

1

Во-первых, для 3904 ГБ памяти требуется только 42 бита для адресации. Он состоит всего из 3 904 000 000 000 байтов вместо того, что вы рассчитали

PS C:\> [math]::Log(3904GB, 2)
41.9307373375629

Технически, даже на 64-битной машине, если вы используете менее чем ~ 4 миллиарда целых чисел (максимальный размер 32-битного целого), то мне интересно, почему вы не можете просто указывать 32-битные указатели. Таким образом, указатели будут 32-битными, пока вы не исчерпаете пространство, тогда вы можете начать использовать 64-битные указатели. Тогда это даст вам немного больше места для большего количества объектов.

x32 ABI - это 64-битный x86 ABI , использующий 32-битные указатели. Процессы имеют только 32-разрядное адресное пространство, что означает, что они не могут использовать более 4 ГБ памяти (это не проблема для большинства пользовательских приложений), но они смогут использовать все большее и большее пространство регистров. Пространство глобальной памяти по-прежнему составляет 64 бита, поскольку оно фиксировано аппаратно, поэтому 32-разрядный указатель будет использоваться в качестве смещения к базовому адресу процесса вместо прямого указателя. Реализация просто так

void* getRealPointer(uintptr_t base_addr, uint32_t ptr)
{
    return (void*)(base_addr + ptr); // value stored in pointer is the offset/distance from base
}

Этот метод также распространен во многих других 64-разрядных архитектурах, таких как Sparc (почему Linux на архитектуре sparc64 использует 32-разрядные указатели в пользовательском пространстве и 64-разрядные указатели в пространстве ядра?), MIPS или PowerPC, поскольку на переходном этапе до 64-битных они не увеличили количество регистров, таких как x86 и ARM, что означает, что 32-битный процесс, вероятно, быстрее, чем 64-битный, если ему не требуется 64-битная математика или более 2/3/4ГБ баран

На 64-разрядных процессорах, таких как G5, Debian PPC использует 64-разрядное ядро с 32-разрядным пользовательским пространством. Это связано с тем, что 64-разрядные процессоры PowerPC не имеют «32-разрядного режима», как архитектура Intel 64/AMD64. Следовательно, 64-разрядные программы PowerPC, которым не нужны 64-разрядные математические функции, будут работать несколько медленнее, чем их 32-разрядные аналоги, поскольку 64-разрядные указатели и длинные целые числа занимают вдвое больше памяти, быстрее заполняют кэш ЦП и, следовательно, требуют большего частые обращения к памяти.

https://lwn.net/Articles/395894/

Тем не менее, вы не можете просто использовать 32-битные указатели, until you run out of space then start using 64-bit pointers, что не имеет смысла. Тип всегда имеет фиксированный размер. Если вы зарезервируете место только для 32-битного указателя, что произойдет, если вам нужно использовать 64-битные указатели? Где вы будете хранить верхнюю часть?


Поэтому, если бы у нас были 32-разрядные указатели, указывающие на 32-разрядные фрагменты в 64-разрядной памяти, я не уверен, как это будет выглядеть или иметь в виду

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

Будет проще представить, что память состоит из серии линейных ячеек , которые идентифицируются уникальными идентификаторами. Эти идентификаторы - это то, что мы обычно называем "адрес", и то, что хранится в указателях. Размер ячейки обычно составляет 1 байт в современных системах (т. Е. Адресно-байтовая память). Однако многие старые системы, такие как Unisys или PDP, используют адресную память со словом, в котором ячейка содержит слово (в случае этих архитектур 36 бит длиной). Следовательно, в этих системах char* будет больше, чем int* так как вам понадобится еще несколько бит для хранения позиции байта, к которому вы хотите обратиться

Я не совсем понимаю вашу диаграмму, но людям редко приходится обращаться с каждым таким битом, так как это, очевидно, уменьшает общий объем памяти, который мы можем адресовать. Хотя, честно говоря, существует несколько архитектур с битовой адресацией памяти, в основном встроенные системы. Если вам нужно 32-битное младшее 64-битное значение, когда вы предоставляете процессору 32-битный адрес, но это не сработает. Для адресации каждой половины вам понадобится еще один значащий бит вместо половины количества битов, подобных этому. Принцип прост: если мы используем больший размер ячейки, чем в том же объеме памяти, требуется меньше ячеек, что означает, что для идентификатора требуется меньше битов; и наоборот. На аппаратном уровне размер ячейки обычно фиксирован.

Ниже приведен пример для первых 16 байтов в памяти

╔══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╗
║ 0000 │ 0001 │ 0010 │ 0011 │ 0100 │ 0101 │ 0110 │ 0111 │ 1000 │ 1001 │ 1010 │ 1011 │ 1100 │ 1101 │ 1110 │ 1111 ║
╠══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╪══════╣
║ b0   │ b1   │ b2   │ b3   │ b4   │ b5   │ b6   │ b7   │ b8   │ b9   │ b10  │ b11  │ b12  │ b13  │ b14  │ b15  ║
╟──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────┼──────┴──────╢
║ w0 000      │ w1 001      │ w2 010      │ w3 011      │ w4 100      │ w5 101      │ w6 110      │ w7 111      ║
╟─────────────┴─────────────┼─────────────┴─────────────┼─────────────┴─────────────┼─────────────┴─────────────╢
║ dw0 00                    │ dw1 01                    │ dw2 10                    │ dw3 11                    ║
╟───────────────────────────┴───────────────────────────┼───────────────────────────┴───────────────────────────╢
║ o0                                                    │ o1                                                    ║
╚═══════════════════════════════════════════════════════╧═══════════════════════════════════════════════════════╝

Вы также можете посмотреть на иллюстрации в этом ответе

Если мы обращаемся к каждому 2-байтовому слову, тогда N-е слово будет иметь байтовый адрес как N * 2. То же самое для любых других размеров чанка, где реальное смещение может быть вычислено как offset*sizeof(chunk) . В результате 2 младших бита в 4-байтовом выровненном адресе 3 младших бита в 8-байтовом выровненном адресе всегда равны нулю. Если вы не используете адресно-адресные указатели, то эти младшие биты можно использовать для хранения данных, которые называются теговыми указателями.

64-битная JVM использует эту технику со сжатыми Oops. См. Хитрость, лежащую в основе сжатых Oops объектов JVM в Java, всегда выровненных по 8 байтов, поэтому они могут адресовать 8 * 4 = 32 ГБ памяти с 32-битным адресом.

Управляемые указатели в куче Java указывают на объекты, которые выровнены по 8-байтовым границам адресов. Сжатые операции представляют управляемые указатели (во многих, но не во всех местах в программном обеспечении JVM) как 32-битные смещения объектов из 64-битного базового адреса кучи Java. Поскольку это смещения объектов, а не смещения байтов, их можно использовать для адресации до четырех миллиардов объектов (не байтов) или размера кучи до 32 гигабайт. Чтобы использовать их, они должны быть масштабированы в 8 раз и добавлены к базовому адресу кучи Java, чтобы найти объект, к которому они относятся. Размеры объектов, использующих сжатые значения, сравнимы с размерами в режиме ILP32.

https://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#compressedOop

Инструкции, работающие с немедленным обращением в большинстве архитектур RISC, также хранят слово address, поскольку нет смысла тратить драгоценное пространство, экономя эти всегда нулевые биты. Например, инструкции MIPS для ветвления и перехода: JAL, J, BEQ, BLEZ, BGTZ ...

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .