Щоб вирішити питання, яке ви опублікували в кількох коментарях (які, я думаю, вам слід відредагувати у своєму дописі):
Що я не розумію, це те, як комп'ютер знає, коли він читає значення змінної з адреси та адреси, наприклад 10001, якщо це int або char. Уявіть, що я натискаю програму під назвою anyprog.exe. Відразу код починає виконуватись. Чи містить цей файл EXE інформацію про те, чи зберігаються змінні як у або char?
Тож давайте додамо до нього якийсь код. Скажімо, ви пишете:
int x = 4;
І припустимо, що він зберігається в оперативній пам’яті:
0x00010004: 0x00000004
Перша частина - адреса, друга частина - значення. Коли ваша програма (яка виконується як машинний код) працює, все, на що вона бачить, 0x00010004
- це значення 0x000000004
. Він не "знає" тип цих даних, і не знає, як він повинен "використовуватись".
Отже, як у вашій програмі з'ясовується правильна справа? Розглянемо цей код:
int x = 4;
x = x + 5;
У нас тут є читання та запис. Коли ваша програма читає x
з пам'яті, вона знаходить 0x00000004
там. І ваша програма знає, що додати 0x00000005
до неї. А причина, по якій ваша програма «знає», це дійсна операція, полягає в тому, що компілятор гарантує, що операція є дійсною через безпеку типу. Ваш компілятор уже перевірив, що ви можете додавати 4
та 5
разом. Отже, коли ваш бінарний код працює (exe), це підтвердження не повинно проводити. Він просто виконує кожен крок наосліп, припускаючи, що все в порядку (погані речі трапляються, коли вони насправді не є нормальними).
Ще один спосіб подумати про це такий. Я надаю вам цю інформацію:
0x00000004: 0x12345678
Той самий формат, що і раніше - адреса зліва, значення праворуч. Якого типу є значення? На даний момент ви знаєте стільки ж інформації про це значення, скільки і ваш комп’ютер, коли він виконує код. Якби я сказав вам додати до цього значення 12743, ви могли б це зробити. Ви не маєте поняття, якими будуть наслідки цієї операції для всієї системи, але додавання двох чисел - це те, що вам справді добре, тож ви могли це зробити. Це робить значення int
? Не обов’язково - все, що ви бачите, це два 32-бітні значення та оператор додавання.
Можливо, деяка плутанина - це повернення даних назад. Якщо у нас є:
char A = 'a';
Як комп'ютер знає відображатись a
у консолі? Ну, є багато кроків до цього. Перший - це перейти до A
пам'яті s в пам'яті та прочитати:
0x00000004: 0x00000061
a
Шестнадцяте значення для ASCII становить 0x61, тому вищезгадане може бути чимось, що ви побачите в пам'яті. Тож тепер наш машинний код знає ціле значення. Звідки це знати, щоб перетворити ціле значення в символ для його відображення? Простіше кажучи, компілятор обов'язково здійснив усі необхідні кроки для здійснення цього переходу. Але сам ваш комп'ютер (або програма / exe) не має уявлення про тип цих даних. Це 32-бітове значення може бути що завгодно - int
, char
, половина double
, покажчик, частина масиву, частина string
, частина інструкції і т.д.
Ось коротка взаємодія, яку може мати ваша програма (exe) з комп'ютером / операційною системою.
Програма: Я хочу запустити. Мені потрібно 20 Мб пам'яті.
Операційна система: знаходить 20 вільних МБ пам'яті, які не використовуються, і передає їх
(Важлива примітка полягає в тому, що це може повернути будь-які 20 вільних МБ пам'яті, вони навіть не повинні бути суміжними. На даний момент програма тепер може працювати в пам'яті, яку вона має, не розмовляючи з ОС)
Програма: Я припускаю, що перше місце в пам'яті - це 32-розрядна ціла змінна x
.
(Компілятор гарантує, що доступ до інших змінних ніколи не торкнеться цього місця в пам'яті. У системі немає нічого, що говорить, що перший байт є змінною x
, або що ця змінна x
ціла. Аналогія: у вас є мішок. Ви кажете людям, що Ви будете класти в цю сумку лише кульки жовтого кольору. Коли хтось пізніше щось витягне з сумки, то було б шокуюче, що вони витягнуть щось синє чи кубик - щось жахливо пішло не так. Те саме стосується комп’ютерів: ваш Програма тепер припускає, що перше місце пам’яті є змінною x, і це ціле число. Якщо що-небудь ще написано над цим байтом пам'яті або вважається, що це щось інше - трапилося щось жахливе. Компілятор забезпечує такі речі речей не трапиться)
Програма: Тепер я напишу 2
на перші чотири байти, де я вважаю, що x
знаходиться.
Програма: Я хочу додати 5 до x
.
Читає значення X у тимчасовому регістрі
Додає 5 до тимчасового реєстру
Зберігає значення тимчасового регістра назад у перший байт, який досі вважається таким x
.
Програма: Я припускаю, що наступний доступний байт - це змінна char y
.
Програма: Я напишу a
на змінну y
.
Для пошуку значення байтів використовується бібліотека a
Байт записується на адресу, яку передбачає програма y
.
Програма: Я хочу відобразити вміст y
Читає значення у другому місці пам'яті
Використовує бібліотеку для перетворення з байта в символ
Використовує графічні бібліотеки для зміни екрана консолі (встановлення пікселів від чорного до білого, прокрутка однієї лінії тощо)
(І продовжується звідси)
Напевно, ви зациклювались на тому, що відбувається, коли першого місця в пам'яті вже немає x
? або другого вже немає y
? Що відбувається, коли хтось читає x
як вказівник char
чи y
як? Словом, трапляються погані речі. Деякі з цих речей мають чітко визначену поведінку, а деякі - невизначену поведінку. Невизначена поведінка - це саме те - все може статися, від нічого зовсім, до збоїв програми чи операційної системи. Навіть чітко визначена поведінка може бути шкідливою. Якщо я можу змінити x
вказівник на свою програму і дозволити вашій програмі використовувати її як покажчик, то я можу змусити вашу програму почати виконувати мою програму - саме це і роблять хакери. Компілятор є там, щоб переконатися, що ми не використовуємо його int x
якstring
та речі такого характеру. Машинний код сам по собі не знає типів, і він буде робити лише те, що вказує інструкція. Існує також велика кількість інформації, виявленої під час виконання: якими байтами пам'яті програма дозволяє використовувати? Починається x
з першого байту чи 12-го?
Але ви можете собі уявити, як жахливо було б насправді писати такі програми (а можна, мовою асемблера). Ви починаєте з "декларування" своїх змінних - ви кажете собі, що байт 1 є x
, байт 2 є y
, і, коли ви пишете кожен рядок коду, завантажуючи і зберігаючи регістри, ви (як людина) повинні пам'ятати, що це таке, x
а яке один з них є y
, тому що система не має уявлення. І ви (як людина) повинні пам'ятати , які типи x
і y
є, тому що ще раз - система не має ні найменшого уявлення.