Чому книги кажуть: "компілятор виділяє простір для змінних в пам'яті"?


18

Чому книги кажуть: "компілятор виділяє простір для змінних в пам'яті". Хіба це не виконуваний файл, який це робить? Я маю на увазі, наприклад, якщо я пишу наступну програму,

#include <iostream>
using namespace std;

int main()
{
   int foo;
   return 0;
}

і скомпілюйте його і отримайте виконуваний файл (нехай це буде program.exe). Тепер, якщо я запускаю program.exe, цей виконуваний файл сам буде командувати виділити деякий простір для змінної foo. Не буде? Поясніть, будь ласка, чому книги продовжують говорити: "компілятор зробить це ... зроби це".


11
про які книги ви говорите?
wirrbel

4
Ваше "пов'язане питання" має бути окремим питанням.
SShaheen

sizeofПитання в даний час знаходиться на Чому SizeOf називається оператором часу компіляції?

Компілятор генерує код, який робить те чи інше, про що вони говорять. прямо чи опосередковано.
old_timer

FYI stackoverflow.com/questions/7372024 / ... і зверніть увагу , що компілятор може прийняти рішення про зміну місця розташування сприймається змінної в пам'яті для вирівнювання наприклад: stackoverflow.com/questions/17774276 / ...
NoChance

Відповіді:


20

Ви праві, що компілятор як такий відсутній, коли ваша програма фактично працює. І якщо він працює на іншій машині, компілятор вже не доступний.

Я думаю, це зробити чітке розмежування пам’яті, фактично виділеної вашим власним кодом. Компілятор вставить у вашу програму код, який виконує розподіл пам'яті (наприклад, використання нових, malloc або подібних команд).

Тому книги використовують "компілятор робить те чи інше", щоб сказати, що компілятор додав код, який прямо не згадується у файлах коду. Правда, що це не зовсім те, що відбувається. З цієї точки зору багато речей, згаданих у навчальних посібниках, було б неправильним, але потребуватимуть досить детальних пояснень.


Так, саме тому я повірив. Дякую за швидку відповідь!
Мирний кодер

12
компілятор виділяє для змінної foo на стеці, замінюючи її зміщенням покажчиком стека під час компіляції. Це зовсім не пов’язано з виділенням кучі, що робиться mallocet. ін.
wirrbel

@holger: Ви заперечуєте, звичайно, технічно правильно. Але простір стека як такий повинен все-таки виділятися при запуску програми до її використання (що може відбуватися різними способами, іноді залежно від архітектури процесора). Я намагався знайти деякі подробиці, як це відбувається, але не з великим успіхом.
thorsten müller

2
Я думаю, що розмір стека для основного потоку резервується лінкером, а потім обробляється ОС. Для користувацьких потоків він більше схожий на розподіл купи, тобто абонент може виправити розмір під час виконання.
wirrbel

4

Це залежить від змінної. ОС виділяє купу, програма виділить стек, а компілятор виділить простір для глобалів / статики, тобто вони вбудовані в саму програму exe. Якщо ви виділите 1 Мб глобальної пам'яті, ваш розмір EXE збільшиться щонайменше на 1 МБ


1
Це не таке питання.
Філіп

2
насправді це питання ближче до інших, наведених тут відповідей.
wirrbel

@James Ах, це не мій досвід. Наприклад, int test[256][1024]; int main(){ test[0][0]=2; return 0; } цій невеликій програмі виділено 1 МБ, але генерується лише мені об'єктний файл 1,4 Кб та виконуваний 8,4 Кб. Однак він повинен використовувати правильний об'єм оперативної пам'яті.
Гарет Клаборн

1
Чи не повинні бути тільки команди розподілу, що зберігаються для глобальних точок? Якщо ви жорстко закодували всі значення за допомогою примітивів, таких як int або char, розмір виконуваного файлу, безумовно, збільшиться більше, ніж кількість доданих змінних. Такі як int a1=1,a2=2,... аж до ... , a1048576=1048576;Тільки тоді ви точно отримаєте щось більше, ніж на 1 мб, я думаю.
Гарет Клаборн

2
Це все, що вносить дані в розділ BSS exe
Джеймс

4

що компілятор буде робити - це взяти ваш код і скласти його в машинний код. Те, що ви згадуєте, - хороший приклад, коли компілятору потрібно лише перекласти.

Наприклад, коли пишеш

int foo;

Ви можете бачити, що як "я повідомляю компілятору [ у висновку, який він генерує ], вимагайте, щоб комп'ютер зарезервував достатню кількість оперативної пам’яті для int, на яку я можу посилатися пізніше. Компілятор, ймовірно, використовує ідентифікатор ресурсу або якийсь механізм для відстеження foo в машинним кодом, ви можете використовувати foo в текстовому файлі, а не писати збірку! Ура !

Тож ви також можете поглянути на це, коли компілятор пише лист ( або, можливо, роман / енциклопедію ) на всі цільові процесори та пристрої. Лист написаний бінарними сигналами, які (як правило) можуть бути переведені в різні процесори, змінюючи ціль. Будь-який 'лист' та / або комбо може надсилати всілякі запити та / або дані, як-от будь-ласка, виділіть простір для цієї змінної, яку використовував програміст.


3

Говорячи, що "компілятор виділяє пам'ять", можливо, не є фактично точним у прямому сенсі, але це метафора, яка навіює правильно.

Дійсно, що компілятор створює програму, яка виділяє власну пам'ять. За винятком того, що не програма виділяє пам'ять, а ОС.

Отже, що насправді відбувається, компілятор створює програму, яка описує його вимоги до пам'яті, а ОС приймає це опис і використовує його для розподілу пам'яті. За винятком того, що ОС - це програма, а програми насправді нічого не роблять, вони описують обчислення, які виконуються процесором. За винятком того, що процесор - це справді лише складна електронна схема, а не антропоморфізований маленький гомонкул.

Але має сенс думати про програми та компілятори та процесори як про маленьких людей, які живуть всередині комп'ютера, не тому, що вони є насправді, а тому, що це метафора, яка добре відповідає людському мозку.

Деякі метафори добре допомагають описувати речі на одному рівні абстракції, але не працюють також на іншому рівні. Якщо ви думаєте про рівень компілятора, має сенс описати акт генерації коду, що призведе до виділення пам'яті, коли програма, що компілюється, фактично працює як "розподілення пам'яті". Досить близько, що коли ми думаємо про те, як працює компілятор, ми маємо правильну ідею, і це не так довго, що ми забуваємо, що ми робили. Якщо ми спробуємо використати цю метафору на рівні запущеної програми, вона вводить в оману дивним чином, що саме ви помітили.


0

Це компілятор, який вирішує, де зберігати змінну - може бути в стеці або у вільному реєстрі. Незалежно від рішення про зберігання, прийнятого компілятором, відповідний машинний код для доступу до цієї змінної буде генерований і не може бути змінений під час виконання. У цьому сенсі компілятор відповідає за виділення місця для змінних, а остаточний program.exe просто сліпо діє як зомбі під час виконання.

Тепер не плутайте це з різним динамічним керуванням пам’яттю, як malloc, new або може бути власним управлінням пам’яттю. Компілятори мають справу зі змінним сховищем та доступом, але не важливо, що означає фактичне значення в іншій рамці / бібліотеці. Наприклад:

byte* pointer = (byte*)malloc(...);

За час виконання, malloc може повернути довільне число, але компілятор не хвилює, його все одно, де зберігати це число.


0

Більш точною фразою було б: - "компілятор повідомляє завантажувачу резервувати простір для змінних"

У середовищі C-ish буде три типи простору для змінних:

  • фіксований блок для статичних змінних
  • Великий блок для "автоматичних" змінних зазвичай називають "стеком". Функції захоплюють шматок при вході та відпускають його після повернення.
  • Великий блок під назвою "купа", звідки виділяється керована програмою пам'ять (використовуючи malloc () або подібний API управління пам'яттю.

На сучасній ОС купі пам'ять насправді не резервується, а розподіляється за потребою.


0

Так, ви маєте рацію, у цьому випадку (декларація змінної у функції) пропозиція вашої книги, ймовірно, неправильне: коли ви оголошуєте змінну у функції, вона призначається на стек після введення функції. У будь-якому разі компілятор повинен оптимізувати ситуацію: якщо функція не рекурсивна ( main()є хорошим кандидатом на неї), це нормально "виділити" її час компіляції (на BSS).

(Якщо вам цікаво, де знаходяться ваші змінні, ви можете перевірити це брудно (якщо все-таки ви не хочете вивчати структуру файлів obj, чому б і ні?), Тож ви можете оголосити деякі різні змінні: постійні, статичні, динамічні, malloc()-розподілені і т. д., і відображати їх адреси (використовувати %Xформат printf()для покращення читабельності). Змінні, що знаходяться на стеці, матимуть дуже різні адреси пам'яті.)


0

Єдине, що робиться під час виконання, - це зіткнення покажчика стека на певну суму. Тому компілятор заздалегідь вирішує:

  • скільки місця для стеку знадобиться для функції.
  • При зміщенні від покажчика стека буде розміщена кожна окрема змінна.

Це можна назвати "виділенням", але, звичайно, під час компіляції він займає місце лише в тій моделі, яку має компілятор запущеної програми.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.