(*(volatile unsigned int *))

(*(volatile unsigned int *))詳解  
                                                        


網上查了資料,先看英文的,看看外國人怎麼解釋: 
Using C, I was trying to assign a variable name to a register address so that my 
code would be readable. An example of how to do this is as follows: 
#define DDRA (*(volatile unsigned char *)(0x22)) 
This means that if a register or memory location exists at address 0×22, I can use 
DDRA to read or write to it like so.. 
DDRA = 0x05 

In my C code.The #define looks really cryptic at first. The way to understand this 
is by breaking it down into pieces. 
First of all, 
unsigned char 
means we are using a byte-sized memory location. Byte being 8-bits wide. 
unsigned char * means we are declaring a pointer that points to a byte-sized location. 
(unsigned char *) (0x22) 
means the byte-sized pointer points to address 0×22. The C compiler will refer to 
address 0×22 when the variable DDRA is used. The assembly code will end up using 
0×22 in Load(LD) and Store (STR) insturctions. 
(*(unsigned char *)(0x22)) 
The first asterisk from the left signifies that we want to manipulate the value in 
address 0×22. * means “the value pointed to by the pointer”. 
volatile 
volatile forces the compiler to issue a Load or Store anytime DDRA is accessed as 
the value may change without the compiler knowing it. 

再看看中文的解釋: 
    使用一個 32 位處理器,要對一個 32 位的內存地址進行訪問,可以這樣定義 
#define RAM_ADDR     (*(volatile unsigned long *)0x0000555F) 
    然後就可以用 C 語言對這個內存地址進行讀寫操作了 
    讀:tmp = RAM_ADDR; 
    寫:RAM_ADDR = 0x55; 
定義 volatile 是因爲它的值可能會改變,大家都知道爲什麼改變了; 
如果在一個循環操作中需要不停地判斷一個內存數據,例如要等待 RAM_ADDR 的I 標誌位置
位, 因爲 RAM_ADDR 也是映射在 SRAM 空間, 爲了加快速度,編譯器可能會編譯出這樣的代碼:
把 RAM_ADDR 讀取到 Register 中,然後不停地判斷 Register 相應位。而不會再讀取
RAM_ADDR,這樣當然是不行了,因爲程序或其它事件(中斷等)會改變 RAM_ADDR,結果很
可能是一個死循環出不來了。如果定義成 volatile 型變量,編譯的代碼是這樣的:每次要
操作一個變量的時候都從內存中讀取一次。 
#define rGPACON(*(volatile unsigned long *)0x56000000) 
對於不同的計算機體系結構,設備可能是端口映射,也可能是內存映射的。如果系統結構支
持獨立的 IO地址空間,並且是端口映射,就必須使用匯編語言完成實際對設備的控制,因
爲 C 語言並沒有提供真正的“端口”的概念。如果是內存映射,那就方便的多了。 
舉個例子,比如像寄存器 A(地址假定爲 0x48000000)寫入數據 0x01,那麼就可以這樣設
置了。 
#define A (*(volatile unsigned long *)0x48000000) 
... 
     A = 0x01; 
... 
    這實際上就是內存映射機制的方便性了。其中 volatile 關鍵字是嵌入式系統開發的一個重要特點。上述表達式拆開來分析,首先(volatile unsigned long *)0x48000000的意
思是把 0x48000000 強制轉換成 volatile unsigned long 類型的指針,暫記爲 p,那麼就是
#define A *p, 即A 爲P 指針指向位置的內容了。 這裏就是通過內存尋址訪問到寄存器 A,
可以讀/寫操作。 
用 GCC 編譯時。volatile 所指示的寄存器不進行優化!!! 

理解#define rRTCCON    (*(volatile unsigned char *)0x57000043) //RTC control 
嵌入式系統編程,要求程序員能夠利用 C 語言訪問固定的內存地址。既然是個地址,那麼按
照 C 語言的語法規則,這個表示地址的量應該是指針類型。所以,知道要訪問的內存地址後,
比如 0x57000043, 
   第一步是要把它強制轉換爲指針類型 
(unsigned char *)0x57000043, s3c2410 的rRTCCON是單字節訪問的(怎麼看出來的???
我無法理解),所以 0x57000043 強制轉換爲指向 unsigned char 類型。 
   volatile(可變的)這個關鍵字說明這變量可能會被意想不到地改變,這樣編譯器就不
會去假設這個變量的值了。這種“意想不到地改變”,不是由程序去改變,而是由硬件去改
變——意想不到。 
   第二步,對指針變量解引用,就能操作指針所指向的地址的內容了 
   *(volatile unsigned char *)0x57000043 
   第三步,小心地把#define 宏中的參數用括號括起來,這是一個很好的習慣。 
在嵌入式系統中經常使用到 Volatile,對於volatile 的用法 

編譯器對代碼的優化是指: 
CPU 在執行的過程中,因爲訪問內存的速度遠沒有 cpu 的執行速度快,爲了提高效率,引入了
高速緩存 cache. C 編譯器在編譯時如果不知道變量會被其它外部因素(操作系統、硬件或者
其它線程)修改,那麼就會對該變量進行標識,即優化.那麼這個變量在 CPU的執行過程中,就
會被放到高速緩存 cache 去,進而達到對變量的快速訪問. 在瞭解了優化的概念後,試想如
果我們事先就知道該變量會被外部因素改變,那麼我們就在這個變量定義前加上 Volatile,
這樣編譯器就不會對該變量進行優化.這樣該變量在 cpu 處理的過程當中,就不會被放到高
速緩存 cache 中。 
爲什麼要讓變量在執行的過程中不被放到 cache 中去呢? 
如果變量是被外部因素改變,那麼 cpu 就無法判斷出這個變量已經被改變,那麼程序在執行
的過程中如果使用到該變量,還會繼續使用 cache 中的變量,但是這個變量其實已經被改變
了.需要到內存地址中更新其內容了. 
還有一個原因,在一些寄存器變量或數據端口的使用中,因爲寄存器變量本身也是靠 cache
來處理,爲了避免引起錯誤,也可以使用 volatile修飾符. 

簡單的說使用 volatile的目的就是: 
讓對 volatile 變量的存取不能緩存到寄存器,每次使用時需要重新存取。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章