Що означає декларувати змінну змінну?


9

Багато програм низького рівня використовують летюче ключове слово для типів для картографування пам’яті тощо. Однак я дещо плутаюсь з тим, що це дійсно робить у фоновому режимі. Іншими словами, що це означає, коли компілятор не «оптимізує» адресу пам'яті?


1
Якщо ви читаєте свій вік із volatileзмінної, і він говорить про 5, і ви читаєте його знову в наступному році, ви гарантовано отримаєте 6.
5gon12eder

@ 5gon12eder, я розумію, що мінливі засоби означають, що щось підлягає швидким і легким змінам, але як це працює? : S
Вікатон

Також, залежно від ваших прапорів компіляції, у вашій налагоджувальній машині може відобразитися енергонезалежна змінна "можливо" (скажімо, ви використовуєте код C + Eclipse + gdb), як: "оптимізоване значення", оскільки значення змінної зараз десь у реєстрі. Якщо ви не знаєте, як використовувати засоби / функції налагодження мови збирання, просто оголосіть свою змінну за допомогою летючого модифікатора.

Відповіді:


11

volatile означає якийсь інший процесор чи пристрій вводу / виводу, або щось може змінити змінну з-під вас.

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

Але ви можете прочитати це як 5, то, можливо, система завантажує дані з диска в цю пам'ять, змінюючи їх на 500. Якщо ви хочете, щоб ваша програма читала свіже значення 500, вам потрібен компілятор, щоб не надто спритно використовувати раніше прочитане 5. Вам потрібно сказати, щоб перезавантажувати значення кожного разу. Ось що і volatileробить.

Аналогія для 5-річних дітей
Скажімо, ви поклали на стіл великий аркуш паперу. В одному кутку листа, ви запишіть поточну оцінку поточної гри 3 to 4. Потім ви переходите до протилежної сторони столу і починаєте писати розповідь про гру. Ваш друг, який спостерігає за грою, оновлює рахунок у цьому куті під час гри. Вона стирає 3 to 4і пише 3 to 5.

Коли ви збираєтеся вкласти рахунок гри у свою історію, ви можете:

  1. Запишіть останню прочитану оцінку 3 to 4, із задоволенням припускаючи, що вона не змінилася (або не маючи на увазі, чи це було), або
  2. Пройдіться до протилежної сторони столу, щоб прочитати поточний бал (який, здається, 3 to 5зараз), і поверніться назад. Ось так діє volatileзмінна.

11

volatile означає дві речі:

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

  2. Акт зберігання значення до змінної змінної - це "побічний ефект", який можна спостерігати ззовні, тому компілятору заборонено видаляти акт збереження значення; наприклад, якщо два значення зберігаються в рядку, тоді компілятор повинен насправді зберігати значення двічі.

Як приклад:

i = 2; 
i = i; 

Компілятор повинен зберігати число два, читати змінну i, зберігати змінну, яку він читав, в i.

Існує ще одна ситуація: якщо функція використовує, setjmpа потім longjmpвикликається, всі мінливі локальні змінні функції гарантовано зберігають останнє значення - це не стосується енергонезалежних локальних змінних.


Тут є деякі тонкі проблеми. Одна з найтонших проблем полягає в тому, що ви характеризуєте летючі читання як характеристику змінної, адже вони насправді є характеристикою доступу до змінної . Якщо у нас є змінна iта значення pi = &i, то x = *piчитання з i, але це читання не гарантується, що воно має мінливу семантику.
Ерік Ліпперт

1
@EricLippert: Якщо iоголошено як volatile int iтоді, його piпотрібно оголосити як volatile int *pi, у такому випадку *piце нестабільний доступ, ні?
Джон Перді

2

Абстрактне пояснення
І C, і C ++ мають поняття абстрактної машини . Коли в коді використовується значення деякої змінної, абстрактна машина каже, що реалізація має отримати доступ до значення цієї змінної. Код форми statement_A; statement_B; statement_C;повинен бути виконаний у точно визначеному порядку. Вирази, спільні для цих трьох тверджень, повинні бути перераховані щоразу, коли вони виникають.

На абстрактних машинах, враховуючи послідовність висловлювань statement_A; statement_B; statement_C;, реалізація спочатку повинна виконуватись statement_Aу повному обсязі, потім statement_B, і нарешті statement_C. Реалізація не може пам'ятати, що ви присвоїли ageзначення 5. Кожне твердження, що посилається, ageзамість цього має отримати доступ до значення цієї змінної.

volatileКлючове слово не буде необхідним, якщо реалізація строго виконується кодом C або C ++ відповідно до технічних характеристик абстрактних машин. Анотаційні машини C і C ++ не мають поняття регістрів, не мають загальних піддепресій, а порядок виконання - строгий.

В обох мовах також є ніби правила. Реалізація відповідає стандарту до тих пір, поки ця реалізація веде себе так, ніби виконувала речі відповідно до абстрактних специфікацій машини. Компілятор може припустити, що енергонезалежні змінні не змінюють значення між призначеннями. Поки це не порушує as-ifправило, послідовність statement_A; statement_B; statement_C;може бути реалізована, виконавши частину statement_C, потім частину statement_A, потім все statement_B, потім решту statement_Aі, нарешті, решту statement_C.

Ці правила, ніби не застосовуються до volatileзмінних. Що стосується volatileзмінних та функцій, то реалізація повинна виконувати саме те, що ви їй наказали робити, і саме в тому порядку, в якому ви їй сказали робити речі.

Існує зворотний бік у специфікації абстрактних машин: це повільно. Одним із позитивних аспектів C та C ++ порівняно з іншими мовами є те, що вони досить швидкі. Це не було б випадком, якби код виконувався на цих абстрактних машинах. Правила -ніби - це те, що дозволяє C і C ++ бути настільки швидкими.

Відповідь ELI5

що це означає, коли компілятор не «оптимізує» адресу пам'яті?

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


1

(не) мінливий - підказка для компілятора, як оптимізувати код (з точки зору згенерованого коду збірки):

  • енергонезалежний означає, що ваш поточний компілятор вирішує, де буде розміщена змінна або як значення змінної s передається підпрограмі
    • у фіксованій адресі пам'яті,
    • на стеці [відносно поточного стек-покажчика процесорів],
    • на купі [відносно поточного базового покажчика процесорів],
    • в регістрі процесора,
    • ...
  • мінливий означає, що компілятор не може оптимізувати змінну, оскільки щось інше поза контролем main-cpu-s (тобто окремий іо-процесор) може змінити це значення.

0

Відповіді здаються досить послідовними, але пропускають важливий момент. Ви говорите компілятору, що хочете виділити простір, і для кожного доступу читайте АБО ЗАПИСЬ, ви хочете, щоб він виконав цей доступ. Ми не хочемо, щоб він чомусь оптимізував ті доступи чи цю змінну.

Так, одна причина полягає в тому, що хтось інший може змінити це значення для нас. Ще одна причина полягає в тому, що ми можемо змінити це значення для когось іншого. Що хтось інший - це той, хто його змінює для нас, або той, для якого ми його змінюємо, може бути апаратним / логічним чи програмним забезпеченням. Він часто використовується для визначення доступу для контролю та реєстрів статусу в програмах, вбудованих в голий метал, запису на апаратне читання або їх читання. А також програмне забезпечення, що розмовляє з програмним забезпеченням, пояснюється в інших відповідях.

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

Іноді ви побачите, що раніше просто спалювали час, елементарний світлодіодний мерехтіння, привітний світ голого металу, може використати мінливу для змінної, яка нараховує до великої кількості просто для того, щоб спалити час, щоб людське око побачило світло змінити стан. Більш досконалі приклади, а потім використання таймерів або інших подій для запису часу.

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