---
tags: C
---
# Programming Languages C - volatile
slide: https://hackmd.io/@SquirrelPanda/rkaknIkXO
{%hackmd ryr9Ug6sd %}
---
## 說明
::: info
volatile 是其中一種修飾符號, 代表著固定該變數的記憶體位置, 與 static 不同的是, 將用來告訴最佳化編譯器不要對使用到該變數的部分進行優化.
:::
一般編譯器在進行優化時會做到簡化程式碼、攤開程式碼等等方式, 但畢竟優化的規則也是人寫的, 某些情況下反而會因優化造成問題, 舉例來說就像 [wikipedia](https://en.wikipedia.org/wiki/Volatile_(computer_programming)) 所舉的例子:
- 首先我們宣告一個 static int 的變數 foo, 此變數會在 bar function 以外都沒有實作任何賦值的動作, 只會在硬體相關 Register 行為時改變.
```c=
static int foo;
void bar(void) {
foo = 0;
while (foo != 255)
;
}
```
- 經最佳編譯器處理後, 會被優化成這樣:
```c=
void bar_optimized(void) {
foo = 0;
while (true)
;
}
```
- 我們可以發現到, 最佳化編譯器因為沒有看到任何代碼修改 foo 的值而假設他永遠是 0, 進而替換成 while(true), 使得原本的判斷是改變. 因此, 我們需要將原式改成以下:
```c=
static volatile int foo;
void bar (void) {
foo = 0;
while (foo != 255)
;
}
```
而針對 volatile 可能使用的地方, 在 ISO/IEC 9899:1999(E) -- Programming Languages -- C (p121) 也有提到 :

:::info
因此當我們在處理與硬體相關的多執行序、中斷機制等, 需要避免最佳化或記憶體重新排列造成問題時就會用到.
:::
另外需要注意的是, 針對加上了 volatile 的變數, 在使用上也要注意, 舉例來說:
- 這是一個計算平方的 function, 輸入的參數我們加上了 volatile.
```c=
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
```
- 然而, 因為 *ptr 隨時有可能會被改變, 有機會造成 $a \neq b$ 的狀況, 這樣就不是平方了, 因此我們應該先把值接出來, 修改如下:
```c=
int square(volatile int *ptr)
{
int a;
a = *ptr;
return a * a;
}
```
## 結語
對於會直接操控 register 的 FW 來說, volatile 一定要會用的部分, 有關最佳化的問題也是會常遇到的狀況, 瞭解而不誤用十分重要.
## 其他
### ARM CMSIS-5.3.0
- CMSIS是ARM所提供的介面, 裡面就會大量使用到 volatile, 可查看下面定義:
<core_cm0.h>
```c=151
/* IO definitions (access restrictions to peripheral registers) */
/**
\defgroup CMSIS_glob_defs CMSIS Global Defines
<strong>IO Type Qualifiers</strong> are used
\li to specify the access to peripheral variables.
\li for automatic generation of peripheral register debug information.
*/
#ifdef __cplusplus
#define __I volatile /*!< Defines 'read only' permissions */
#else
#define __I volatile const /*!< Defines 'read only' permissions */
#endif
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
/* following defines should be used for structure members */
#define __IM volatile const /*! Defines 'read only' structure member permissions */
#define __OM volatile /*! Defines 'write only' structure member permissions */
#define __IOM volatile /*! Defines 'read / write' structure member permissions */
```
## 參考資料
- [ISO/IEC 9899 - Programming languages - C](http://www.open-std.org/jtc1/sc22/wg14/www/standards.html)
- [wikipedia - volatile (computer programming)](https://en.wikipedia.org/wiki/Volatile_(computer_programming))
- [C語言中的volatile用法](https://www.itread01.com/content/1541733250.html)