Використання volatile змінних в сі

Рейтинг: 5/5


Чи стикалися ви під час роботи з Сі або Сі ++ кодом з наступними ситуаціями?

- код, який прекрасно працює, поки ви не включите оптимізацію

- код, який прекрасно працює, поки заборонені переривання

- завдання ОСРВ, які чудово працюють в ізоляції, поки не створена якась інша задача

Якщо ви відповіли «так» на одне з цих тверджень, швидше за все ви не використовуєте ключове слово volatile. Ви не самотні. Використання цього специфікатор погано вивчено багатьма програмістами, оскільки більшість книг з програмування на мові Сі не приділяють цій темі належної уваги.

Ключове слово volatile пишеться до або після типу даних оголошується змінної.

volatile intfoo;

int volatilefoo;

Покажчики на volatile змінні оголошуються так.

volatile int * pReg;

int volatile * pReg;

Volatile покажчики на НЕ volatile змінні зустрічаються вкрай рідко (думаю, я використовував їх лише один раз), але я про всяк випадок дам їх синтаксис:

int * volatile p;

І, для повноти, якщо вам знадобиться volatile покажчик на volatile змінну, слід написати:

int volatile * volatile p;

Якщо ви використовуєте volatile для структури (struct) або об'єднання (union), дія специфікатор буде поширюватися на весь вміст структури / об'єднання. Якщо ви не хочете цього, то можете застосувати специфікатор volatile до окремих елементів структури / об'єднання.

Правильне використання специфікатор VOLATILE

Мінлива повинна бути оголошена з ключовим словом volatile щоразу, коли її значення може змінитися несподівано.

uint8_t * pReg = (uint8_t *) 0x1234;

// Wait for register to become non-zero

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

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

uint8_t volatile * pReg = (uint8_t volatile *) 0x1234;

Асемблерний код тепер виглядає наступним чином:

Необхідний хід процесу досягнуто.

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

Стосовно до програмування мікроконтролерів AVR, немає ніякої необхідності у використанні покажчиків на периферійні регістри, тому що код в цьому випадку виходить дуже громіздким. Pashgan.

Програма обробки переривання (ISR)

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

int etx_rcvd = FALSE;

Схожі статті