Це було частково засноване на процесорі.
У 1980-і роки більшість комп'ютерів мали 16-бітну архітектуру,
тому покажчик міг би отримати доступ до віртуального адресного простору
2 16 (65536) байтів.
Це, природно, вважалося занадто обмежувальним.
Коли сегмент коду відокремлений від інших,
Ви можете мати 2 16 байтів коду (інструкції)
і 2 16 байтів вартості даних, що менш погано.
"Простір даних" програми / процесу
(використовуючи терміни в найширшому розумінні) може включати
- Ініціалізовані дані, в тому числі
- Рядки (наприклад,
printf("Hello, world\n");
),
- Ініціалізовані змінні (наприклад,
int i = 42;
), і
- У деяких випадках у коді використовуються константи (наприклад,
y = x + 17;
),
- Неініціалізовані змінні
(наприклад,
int j;
, char mydata[80];
у статичних / глобальних контекстах),
- Динамічно розподілена пам'ять (
malloc
, new
), і
- Стек (аргументи функції, інформація збереження / відновлення та локальні змінні).
Я, можливо, щось залишаю, але регістри насправді не враховуються
(вони по суті є особливим випадком неініціалізованих змінних)
і спільна пам'ять виходить за рамки цієї дискусії.
Зверніть увагу, що, з вищенаведеного,
тільки ініціалізовані дані повинні бути збережені в виконуваному файлі -
простір для неініціалізованих змінних і
стек автоматично виділяється ОС, коли програма виконується.
Таким чином, компілятори повинні відстежувати ініціалізовані дані
і неініціалізовані змінні окремо.
Інший зморшок - це процесор Intel 8086
(прапрадід Пентіума)
вимагає, щоб кожен сегмент був одним великим, суміжним блоком пам'яті.
Ядро Unix складається з одного великого блоку коду і одного великого блоку даних
(ініціалізовані дані та неініціалізовані змінні),
але для кожного процесу використовується окремий стек.
Тому 8086 вимагала здатності
мати стек в іншому сегменті від усіх інших даних.
Тут багато інформації про це в Інтернеті.
Наприклад, у Вікіпедії: