嵌入式C語言強化筆記--__I、 __O 、__IO
__I、 __O、__IO是什麼意思?
這是ST庫裡面的巨集定義,定義如下:
#define __I volatileconst
#define __O volatile
#define __IO volatile
顯然,這三個巨集定義都是用來替換成 volatile 和 const的,所以我們先要了解這兩個關鍵字的作用:
volatile
簡單的說,就是不讓編譯器進行優化,即每次讀取或者修改值的時候,都必須重新從記憶體或者暫存器中讀取或者修改。
一般說來,volatile用在如下的幾個地方:
1、中斷服務程式中修改的供其它程式檢測的變數需要加volatile;
2、多工環境下各任務間共享的標誌應該加volatile;
3、儲存器對映的硬體暫存器通常也要加volatile說明,因為每次對它的讀寫都可能由不同意義;
我認為這是區分C程式設計師和嵌入式系統程式設計師的最基本的問題。搞嵌入式的傢伙們經常同硬體、中斷、RTOS等等打交道,所有這些都要求用到 volatile變數。不懂得volatile的內容將會帶來災難。假設被面試者正確地回答了這些問題(嗯,懷疑是否會是這樣),我將稍微深究一下,看一下這傢伙是不是直正懂得volatile完全的重要性。
1)一個引數既可以是const還可以是volatile嗎?解釋為什麼。
2); 一個指標可以是volatile 嗎?解釋為什麼。
3); 下面的函式有什麼錯誤:
intsquare(volatileint*ptr)
{
return *ptr **ptr;
}
1)是的。一個例子是隻讀的狀態暫存器。它是volatile因為它可能被意想不到地改變。它是const因為程式不應該試圖去修改它。
2); 是的。儘管這並不很常見。一個例子是當一箇中斷服務子程式修該一個指向一個buffer的指標時。
3) 這段程式碼有點變態。這段程式碼的目的是用來返指標*ptr指向值的平方,但是,由於*ptr指向一個volatile型引數,編譯器將產生類似下面的程式碼:
intsquare(volatileint*ptr)
{
inta,b;
a =*ptr;
b =*ptr;
return a *b;
}
由於*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結果,這段程式碼可能返不是你所期望的平方值!正確的程式碼如下:
longsquare(volatileint*ptr)
{
int a;
a =*ptr;
return a *a;
}
const
只讀變數,即變數儲存在只讀靜態儲存區。編譯時,如過嘗試修改只讀變數,則編譯器提示出錯,就能防止誤修改。
const與define
兩者都可以用來定義常量,但是const定義時,定義了常量的型別,所以更精確一些(其實const定義的是隻讀變數,而不是常量)。#define只是簡單的文字替換,除了可以定義常量外,還可以用來定義一些簡單的函式,有點類似內建函式。const和define定義的常量可以放在標頭檔案裡面。(小注:可以多次宣告,但只能定義一次)
const與指標
int me;
const int * p1=&me; //p1可變,*p1不可變 const 修飾的是*p1,即*p1不可變
int *constp2=&me; //p2不可變,*p2可變 const 修飾的是p2,即p2不可變
const int *const p3=&me; //p3不可變,*p3也不可變 前一個const修飾的是 *p3,後一個const 修飾的是p3,兩者都不可變
前面介紹了 volatile 和 const的用法,不知道大家瞭解了沒?瞭解了後,下面的講解就更加容易了:
__I:輸入口。既然是輸入,那麼暫存器的值就隨時會外部修改,那就不能進行優化,每次都要重新從暫存器中讀取。也不能寫,即只讀,不然就不是輸入而是輸出了。
__O:輸出口,也不能進行優化,不然你連續兩次輸出相同值,編譯器認為沒改變,就忽略了後面那一次輸出,假如外部在兩次輸出中間修改了值,那就影響輸出
__IO:輸入輸出口,同上
為什麼加下劃線?
原因是:避免命名衝突
一般巨集定義都是大寫,但因為這裡的字母比較少,所以再新增下劃線來區分。這樣一般都可以避免命名衝突問題,因為很少人這樣命名,這樣命名的人肯定知道這些是有什麼用的。
經常寫大工程時,都會發現老是命名衝突,要不是全域性變數衝突,要不就是巨集定義衝突,所以我們要儘量避免這些問題,不然出問題了都不知道問題在哪裡。
這是ST庫裡面的巨集定義,定義如下:
#define __I volatileconst
#define __O volatile
#define __IO volatile
顯然,這三個巨集定義都是用來替換成 volatile 和 const的,所以我們先要了解這兩個關鍵字的作用:
volatile
簡單的說,就是不讓編譯器進行優化,即每次讀取或者修改值的時候,都必須重新從記憶體或者暫存器中讀取或者修改。
一般說來,volatile用在如下的幾個地方:
1、中斷服務程式中修改的供其它程式檢測的變數需要加volatile;
2、多工環境下各任務間共享的標誌應該加volatile;
3、儲存器對映的硬體暫存器通常也要加volatile說明,因為每次對它的讀寫都可能由不同意義;
我認為這是區分C程式設計師和嵌入式系統程式設計師的最基本的問題。搞嵌入式的傢伙們經常同硬體、中斷、RTOS等等打交道,所有這些都要求用到 volatile變數。不懂得volatile的內容將會帶來災難。假設被面試者正確地回答了這些問題(嗯,懷疑是否會是這樣),我將稍微深究一下,看一下這傢伙是不是直正懂得volatile完全的重要性。
1)一個引數既可以是const還可以是volatile嗎?解釋為什麼。
2); 一個指標可以是volatile 嗎?解釋為什麼。
3); 下面的函式有什麼錯誤:
intsquare(volatileint*ptr)
{
return *ptr **ptr;
}
1)是的。一個例子是隻讀的狀態暫存器。它是volatile因為它可能被意想不到地改變。它是const因為程式不應該試圖去修改它。
2); 是的。儘管這並不很常見。一個例子是當一箇中斷服務子程式修該一個指向一個buffer的指標時。
3) 這段程式碼有點變態。這段程式碼的目的是用來返指標*ptr指向值的平方,但是,由於*ptr指向一個volatile型引數,編譯器將產生類似下面的程式碼:
intsquare(volatileint*ptr)
{
inta,b;
a =*ptr;
b =*ptr;
return a *b;
}
由於*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結果,這段程式碼可能返不是你所期望的平方值!正確的程式碼如下:
longsquare(volatileint*ptr)
{
int a;
a =*ptr;
return a *a;
}
const
只讀變數,即變數儲存在只讀靜態儲存區。編譯時,如過嘗試修改只讀變數,則編譯器提示出錯,就能防止誤修改。
const與define
兩者都可以用來定義常量,但是const定義時,定義了常量的型別,所以更精確一些(其實const定義的是隻讀變數,而不是常量)。#define只是簡單的文字替換,除了可以定義常量外,還可以用來定義一些簡單的函式,有點類似內建函式。const和define定義的常量可以放在標頭檔案裡面。(小注:可以多次宣告,但只能定義一次)
const與指標
int me;
const int * p1=&me; //p1可變,*p1不可變 const 修飾的是*p1,即*p1不可變
int *constp2=&me; //p2不可變,*p2可變 const 修飾的是p2,即p2不可變
const int *const p3=&me; //p3不可變,*p3也不可變 前一個const修飾的是 *p3,後一個const 修飾的是p3,兩者都不可變
前面介紹了 volatile 和 const的用法,不知道大家瞭解了沒?瞭解了後,下面的講解就更加容易了:
__I:輸入口。既然是輸入,那麼暫存器的值就隨時會外部修改,那就不能進行優化,每次都要重新從暫存器中讀取。也不能寫,即只讀,不然就不是輸入而是輸出了。
__O:輸出口,也不能進行優化,不然你連續兩次輸出相同值,編譯器認為沒改變,就忽略了後面那一次輸出,假如外部在兩次輸出中間修改了值,那就影響輸出
__IO:輸入輸出口,同上
為什麼加下劃線?
原因是:避免命名衝突
一般巨集定義都是大寫,但因為這裡的字母比較少,所以再新增下劃線來區分。這樣一般都可以避免命名衝突問題,因為很少人這樣命名,這樣命名的人肯定知道這些是有什麼用的。
經常寫大工程時,都會發現老是命名衝突,要不是全域性變數衝突,要不就是巨集定義衝突,所以我們要儘量避免這些問題,不然出問題了都不知道問題在哪裡。
相關文章
- 嵌入式C語言學習筆記2C語言筆記
- 一文看懂 C 語言 I/O
- c語言筆記C語言筆記
- I/O程式設計技術(檔案IO)筆記綱要梳理程式設計筆記
- HQYJ嵌入式學習筆記——C語言複習day1筆記C語言
- HQYJ嵌入式學習筆記——C語言複習day2筆記C語言
- 檔案管理I/O筆記筆記
- C 語言學習筆記筆記
- C語言學習筆記C語言筆記
- C語言深度剖析-筆記C語言筆記
- C語言指標筆記C語言指標筆記
- C語言與嵌入式C語言的區別C語言
- nodejs筆記-非同步I/ONodeJS筆記非同步
- Java學習筆記之I/OJava筆記
- C語言加強C語言
- C語言學習筆記--C運算子C語言筆記
- c語言強制記憶體轉化引發的問題C語言記憶體
- c++ I/OC++
- 程式設計技巧之嵌入式C語言完全學習筆記及案例[圖]程式設計C語言筆記
- c語言筆記:楊輝三角C語言筆記
- c語言學習筆記===函式C語言筆記函式
- C語言筆記——自定義型別C語言筆記型別
- 瘋子C語言筆記 (string)C語言筆記
- C語言的一些小筆記C語言筆記
- C語言深度剖析——讀書筆記C語言筆記
- I/O埠和I/O記憶體記憶體
- C語言 檔案IO的使用C語言
- 資訊學奧賽--C語言筆記(一)C語言筆記
- C語言學習筆記——位運算C語言筆記
- c語言程式基礎學習筆記C語言筆記
- C語言學習筆記之變數C語言筆記變數
- 考研:C語言複習筆記 [Hex Note]C語言筆記
- 初識C語言(01)—學習筆記C語言筆記
- 嵌入式c語言編碼規範C語言
- 41、C++ Primer 4th筆記,IO庫,格式化IO操作C++筆記
- 優化磁碟I/O優化
- 詳解Go語言I/O多路複用netpoller模型Go模型
- C語言I部落格作業07C語言