C 語言標(biāo)準(zhǔn)定義的 32 個(gè)關(guān)鍵字有什么,分別怎么用份企,用的時(shí)候需要注意到什么,便是這篇文章所要告訴的一切巡莹。內(nèi)容較長司志,先上本篇文章結(jié)構(gòu)思維導(dǎo)圖甜紫。文章結(jié)尾處有 32 個(gè)關(guān)鍵字附錄。
- 修飾類 -
- 1. extern -- 最會帶帽子的關(guān)鍵字 -
- 定義創(chuàng)建了對象并為這個(gè)對象分配了內(nèi)存骂远,聲明沒有分配內(nèi)存
- 相同的定義只能出現(xiàn)一次囚霸,相同的聲明可以出現(xiàn)多次
int i; // 變量的定義
extern int i; // 變量的聲明
void fun(int i, char c); // 函數(shù)的聲明
void fun(int i, char c) {} // 函數(shù)的定義
- 2. auto -
- 編譯器在默認(rèn)的缺省情況下,所有變量都是用 auto 修飾的激才。
- 3. register -- 最快的關(guān)鍵字 -
- 這個(gè)關(guān)鍵字請求編譯器盡可能的將變量存在 CPU 內(nèi)部寄存器中而不是通過內(nèi)存尋址訪問以高效率拓型。注意是盡可能,不是絕對瘸恼。
3.1 寄存器
- 數(shù)據(jù)從內(nèi)存里拿出來先放到寄存器劣挫,然后 CPU 再從寄存器里讀取數(shù)據(jù)來處理,處理完后同樣把數(shù)據(jù)通過寄存器存放到內(nèi)存里,CPU 不直接和內(nèi)存打交道东帅。
3.2 使用 register 修飾符的注意點(diǎn)
- register 變量必須是能被 CPU 寄存器所接受的類型
- register 變量必須是一個(gè)單個(gè)的值,并且其長度應(yīng)小于或等于整型的長度
- register 變量可能不存放在內(nèi)存中冰啃,所以不能用取址運(yùn)算符“&”來獲取 register 變量的地址
- 4. static -- 最名不符實(shí)的關(guān)鍵字 -
關(guān)鍵字 static 有著不尋常的歷史邓夕。起初,在 C 中引入關(guān)鍵字 static 是為了表示退出一個(gè)塊后仍然存在的局部變量。隨后,static 在 C 中有了第二種含義:用來表示不能被其它文件訪問的全局變量和函數(shù)阎毅。為了避免引入新的關(guān)鍵字,所以仍使用 static 關(guān)鍵字來表示這第二種含義焚刚。
4.1 修飾變量
- 變量又分為局部和全局變量,但它們都存在內(nèi)存的靜態(tài)區(qū)
- 靜態(tài)全局變量,作用域僅限于變量被定義的文件中
- 靜態(tài)局部變量,在函數(shù)體里面定義且只能在這個(gè)函數(shù)里用
- 靜態(tài)變量的值不會被銷毀,函數(shù)下次使用時(shí)仍然能用到這個(gè)值
4.2 修飾函數(shù)
- 函數(shù)前加 static 使得函數(shù)成為靜態(tài)函數(shù),指對函數(shù)的作用域僅局限于本文件(所以又稱內(nèi)部函數(shù))
- 5. const 關(guān)鍵字 -
- const 是 constant 的縮寫扇调,并不是英文直譯的用來修飾“常量”矿咕,更精確的說是修飾“只讀變量”,其值在編譯時(shí)不能被使用狼钮,因?yàn)榫幾g器在編譯時(shí)不知道其存儲的內(nèi)容碳柱。
- const 推出的初始目的,正是為了取代預(yù)編譯指令熬芜,消除它的缺點(diǎn)莲镣,同時(shí)繼承它的優(yōu)點(diǎn)。
5.1 const 修飾的只讀變量
- 定義 const 只讀變量涎拉,具有不可變性瑞侮。該變量具有只讀屬性。
5.2 節(jié)省空間,避免不必要的內(nèi)存分配鼓拧,同時(shí) 高效率
- 編譯器通常不為普通 const 只讀變量分配存儲空間半火,而是將它們保存在符號表中,這使得它成為一個(gè)編譯期間的值,沒有了存儲與讀內(nèi)存的操作季俩,使得它的效率也很高钮糖。
- const 定義的只讀變量從匯編的角度來看,只是給出了對應(yīng)的內(nèi)存地址。
5.3 修飾一般變量
- 只讀變量在定義時(shí)酌住,修飾符 const 可以用在類型說明符前店归,也可以用在類型說明符后阎抒。例如:
int const i=2; // 正確
const int j=2; // 正確
5.4 修飾數(shù)組
- 定義或說明一個(gè)只讀數(shù)組可采用如下格式:
int const a[5]={1, 2, 3, 4, 5}; // 正確
const int b[5]={1, 2, 3, 4, 5}; // 正確
5.5 修飾指針
- 先忽略類型名(編譯器解析的時(shí)候也是忽略類型名),我們看 const 離哪個(gè)近娱节∧域龋“近水樓臺先得月”,離誰近就修飾誰肄满。
const int *p; // p 可變谴古,p 指向的對象不可變
int const *p; // p 可變,p 指向的對象不可變
int *const p; // p 不可變稠歉, p 指向的對象可變
const int *const p; // 指針 p 和 p 指向的對象都不可變
5.6 修飾函數(shù)的參數(shù)
- 當(dāng)不希望這個(gè)參數(shù)值被函數(shù)體內(nèi)意外改變時(shí)掰担,const 修飾符也可以修飾函數(shù)的參數(shù),從而防止了使用者的一些無意的或錯(cuò)誤的修改怒炸。
void Fun(const int i);
5.7 修飾函數(shù)的返回值
- const 修飾符也可以修飾函數(shù)的返回值带饱,返回值不可被改變。例如:
const int Fun (void);
- 在另一連接文件中引用 const 只讀變量
extern const int i; // 正確的聲明
extern const int j=10; // 錯(cuò)誤!只讀變量的值不能改變阅羹。
- 6. signed勺疼、unsigned 關(guān)鍵字 -
- 既然計(jì)算機(jī)底層只認(rèn)識 0 和 1 的二進(jìn)制數(shù)字,那么正數(shù)和負(fù)數(shù)是怎么存儲的呢捏鱼?signed 和 unsigned 修飾的變量各有什么特點(diǎn)执庐?
- 答案很簡單。在 32 位計(jì)算機(jī)的內(nèi)部导梆,一個(gè) int 型的整數(shù)由 4 字節(jié) 32 位 0/1 數(shù)字組成轨淌,32 個(gè)數(shù)字中最高位(第一個(gè)數(shù)字)表示符號位并約定最高位如果是 1 則表示負(fù)數(shù),如果是 0 則表示正數(shù)看尼,這樣一來递鹉,一個(gè) 32 位有符號的 int 型變量便能表示 -2147483648~2147483647 之間的數(shù)字,而無符號的 int 型變量便能表示 0~4294967295 之間的數(shù)字藏斩。
- 其中有符號的 int 型變量由 signed 修飾躏结,一般可以省去;無符號的 int 型變量由 unsigned 修飾狰域,不能省去窜觉。
signed int i;
unsigned int love;
signed int u;
- 然而用普通 01 碼(原碼)表示的數(shù)字中 +0 和 -0 各有一種表示方法,且原碼無法北专,具體的計(jì)算機(jī)中負(fù)數(shù)其實(shí)是以補(bǔ)碼的形式存儲的。補(bǔ)碼由反碼 +1 而來旬陡,而反碼由原碼的每一位 0 變成 1拓颓,1 變成 0而來。同時(shí)反碼和補(bǔ)碼的出現(xiàn)使得計(jì)算機(jī)為辨別"符號位"而設(shè)計(jì)的電路不再復(fù)雜描孟。具體的有關(guān)機(jī)器語言中原碼驶睦、反碼和補(bǔ)碼的知識都在我的博客園里寫過砰左,期待之后整理到簡書中來。
- 數(shù)據(jù)類型 -
- 7. 數(shù)據(jù)類型 -
- short场航、int缠导、long、char溉痢、float僻造、double 這六個(gè)關(guān)鍵字代表 C 語言里的六種基本數(shù)據(jù)類型。
7.1 數(shù)據(jù)類型與“模子”
- 在每一個(gè)擁有數(shù)據(jù)類型的變量的聲明時(shí)孩饼,都會分配給該變量特定的內(nèi)存大小空間髓削。放出基本數(shù)據(jù)類型在 32 位操作系統(tǒng)下特定的內(nèi)存空間大小:
- 具體有關(guān)各個(gè)數(shù)據(jù)類型的特點(diǎn)和區(qū)別及其混合運(yùn)算與類型轉(zhuǎn)換等可以參考我在博客園寫的這篇文章镀娶,畢竟本文的重心在“關(guān)鍵字”上立膛。
7.2 變量的命名規(guī)則
- 命名和緩存失效是計(jì)算機(jī)科學(xué)面臨的最難的兩件事。其中符合規(guī)范的變量命名可以直觀地看出代碼的邏輯性梯码,具體命名規(guī)則也同樣加入自己的博客園文章地址宝泵,期待之后整理到簡書中來。
- 8. void 關(guān)鍵字 -
- “色即是空,空即是色”儿奶,void 也有它的妙用 —— void 的字面意思是“空類型”,void *則為“空類型指針”,void *可以指向任何類型的數(shù)據(jù)。
- void 真正發(fā)揮的作用在于:
1 -> 對函數(shù)返回的限定;
2 -> 對函數(shù)參數(shù)的限定罢坝。 - 任何類型的指針都可以直接賦值給 void 廓握,無需進(jìn)行強(qiáng)制類型轉(zhuǎn)換。
void *p1;
int *p2;
p1 = p2;
8.1 void 修飾函數(shù)返回值和參數(shù)
- 如果函數(shù)沒有返回值,那么應(yīng)聲明為 void 類型
在給函數(shù)不加返回值說明時(shí)默認(rèn)為 int 型嘁酿,所以對于沒有返回值的函數(shù)推薦用 void 聲明隙券。另外,加上 void 類型聲明后,也可以發(fā)揮代碼的“自注釋”作用闹司。所謂的代碼的“自注釋”即代碼能自己注釋自己娱仔。 - 如果函數(shù)無參數(shù),那么應(yīng)聲明其參數(shù)為 void
在 C 語言中,可以給無參數(shù)的函數(shù)傳送任意類型的參數(shù),但是在 C++編譯器中編譯同樣的代碼則會出錯(cuò)游桩。所以牲迫,無論在 C 還是 C++中,若函數(shù)不接受任何參數(shù)借卧,一定要指明參數(shù)為 void盹憎。
8.2 void 指針
- 千萬小心又小心使用 void 指針類型。
按照 ANSI(American National Standards Institute)標(biāo)準(zhǔn)铐刘,不能對 void 指針進(jìn)行算法操作陪每,即下列操作都是不合法的:
void * pvoid;pvoid++; // ANSI:錯(cuò)誤
pvoid += 1; // ANSI:錯(cuò)誤
但是大名鼎鼎的 GNU(GNU's Not Unix 的遞歸縮寫)則不這么認(rèn)定,它指定 void *的算法操作與 char *一致。因此下列語句在 GNU 編譯器中皆正確:
pvoid++; // GNU:正確
pvoid += 1; // GNU:正確
因此檩禾,為了兼容兩大標(biāo)準(zhǔn)挂签, 高程序的可移植性,我們可以這樣編寫實(shí)現(xiàn)同樣功能的代碼:
void * pvoid;(char *)pvoid++; // ANSI:正確;GNU:正確(char *)
pvoid += 1; // ANSI:錯(cuò)誤;GNU:正確
- 如果函數(shù)的參數(shù)可以是任意類型指針,那么應(yīng)聲明其參數(shù)為 void *盼产。
典型的如內(nèi)存操作函數(shù) memcpy 和 memset 的函數(shù)原型分別為:
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );
8.3 void 不能代表一個(gè)真實(shí)的變量
- void 不能代表一個(gè)真實(shí)的變量饵婆。
void a; // 錯(cuò)誤
function(void a); // 錯(cuò)誤
- 9. struct 關(guān)鍵字 -
- 常用在網(wǎng)絡(luò)協(xié)議、通信協(xié)議戏售、嵌入式系統(tǒng)侨核、驅(qū)動開發(fā)等地方的 struct 關(guān)鍵字將一些相關(guān)聯(lián)的數(shù)據(jù)打包成一個(gè)整體(結(jié)構(gòu)體),方便使用蜈项。同時(shí)芹关,可以用結(jié)構(gòu)體壓縮參數(shù)個(gè)數(shù)。
9.1 空結(jié)構(gòu)體有多大
- 結(jié)構(gòu)體所占的內(nèi)存大小是其成員所占內(nèi)存之和紧卒。但空結(jié)構(gòu)體呢侥衬?
struct student{
} stu;
- 答案不是 0 而是 1。因?yàn)榫幾g器認(rèn)為任何一種數(shù)據(jù)類型都有其大小跑芳,空結(jié)構(gòu)體的大小又不能大于只有 char 類型的結(jié)構(gòu)體大小轴总,所以 0 < sizeof(stu) <= 1 的情況下,空結(jié)構(gòu)體的大小就定為 1 個(gè) byte博个。
9.2 柔性數(shù)組
- C99 中怀樟,結(jié)構(gòu)中的最后一個(gè)元素允許是未知大小的數(shù)組,這就叫做柔性數(shù)組成員盆佣,但結(jié)構(gòu)中的柔性數(shù)組成員前面必須至少一個(gè)其他成員往堡。
typedef struct st_type {
int i;
int a[];
} type_a;
- 即使這時(shí) sizeof(type_a) 得到的只有 sizeof(int) 的值 —— 4,但這是我們可以進(jìn)行邊長操作共耍,通過以下表達(dá)式給結(jié)構(gòu)體分配內(nèi)存:
type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
- 這時(shí)候 p->item[n] 就能簡單的訪問可變長元素虑灰。而 sizeof(*p) 依舊是 4。
9.3 struct 和 class 的區(qū)別
- 在 C++里 struct 關(guān)鍵字與 class 關(guān)鍵字一般可以通用痹兜,只有一個(gè)很小的區(qū)別穆咐。struct 的成員默認(rèn)情況下屬性是 public 的,而 class 成員卻是 private 的字旭。很多人覺得不好記,其實(shí)很容易对湃。你平時(shí)用結(jié)構(gòu)體時(shí)用 public 修飾它的成員了嗎?既然 struct 關(guān)鍵字與 class 關(guān)鍵字可以通用遗淳,你也不要認(rèn)為結(jié)構(gòu)體內(nèi)不能放函數(shù)了拍柒。
- 10. union 關(guān)鍵字 -
- union 關(guān)鍵字的用法與 struct 的用法非常類似,用來維護(hù)足夠的空間來置放多個(gè)數(shù)據(jù)成員中的“一種”屈暗,而不是為每一個(gè)數(shù)據(jù)成員配置空間拆讯。例子如下:
union StateMachine
{
char character;
int number;
char *str;
double exp;
};
- 一個(gè) union 只配置一個(gè)足夠大的空間以來容納最大長度的數(shù)據(jù)成員,以上例而言,最大長度是 double 型態(tài),所以 StateMachine 的空間大小就是 double 數(shù)據(jù)類型的大小剧包。
- 在 C++里,union 的成員默認(rèn)屬性頁為 public。union 主要用來壓縮空間往果。如果一些數(shù)據(jù)不可能在同一時(shí)間同時(shí)被用到,則可以使用 union。
10.1 大小端模式對 union 類型數(shù)據(jù)的影響
union {
int i;
char a[2];
} *p, u;
p = &u;
p->a[0] = 0x39;
p->a[1] = 0x38;
- 上面的例子中 p.i 的值為多少呢一铅?這就要考慮存儲模式 —— 大端模式和小端模式了陕贮。
- 大端模式(Big_endian):字?jǐn)?shù)據(jù)的高字節(jié)存儲在地地址中,而字?jǐn)?shù)據(jù)的低字節(jié)存放在高地址中潘飘。
- 小端模式(Little_endian)肮之,字?jǐn)?shù)據(jù)的高字節(jié)存儲在高地址中,而字?jǐn)?shù)據(jù)的低字節(jié)則存放在低地址中。
- 11. enum 關(guān)鍵字 -
- 初學(xué)者一般用不到的 enum 數(shù)據(jù)類型其實(shí)很有用處卜录。
11.1 枚舉類型的使用方法
- 一般的定義方式如下:
enum enum_type_name
{
ENUM_CONST_1,
ENUM_CONST_2,
...
ENUM_CONST_n
} enum_variable_name;
- 其中 enum_type_name 是自定義的一種數(shù)據(jù)類型名戈擒,而 emun_varaiable_name 類型是對一個(gè)變量取值范圍的限定,而花括號內(nèi)是它的取值范圍艰毒,及 enum_type_name 類型的變量 emun_varaiable_name 只能取值為花括號內(nèi)的任何一個(gè)值筐高,如果賦給該類型變量的值不在列表中,則會報(bào)錯(cuò)或警告丑瞧。
11.2 枚舉與 #define 宏的區(qū)別
-
define 宏常量是在預(yù)編譯階段進(jìn)行簡單替換柑土,枚舉常量則是在編譯的時(shí)候確定其值。
- 一般在編譯器里绊汹,可以調(diào)試枚舉常量稽屏,但是不能調(diào)試宏常量。
- 枚舉可以一次定義大量相關(guān)的常量西乖,但是 #define 宏一次只能定義一個(gè)狐榔。
- 枚舉可以一次定義大量相關(guān)的常量,而 #define 宏一次只能定義一個(gè)获雕。
- 選擇分支 -
- 12. If else 組合 -
12.1 bool 變量與“零值”進(jìn)行比較
bool bTestFlag = FALSE; // 一般要初始化為 FALSE
if(bTestFlag == 0); // 不好薄腻。容易被誤解為整型變量
if(bTestFlag == TRUE); // 不好。TRUE的值不都為1典鸡。
if(bTestFlag); // 推薦
12.2 float 變量與“零值”進(jìn)行比較
float fTestVal = 0.0;
if(fTestVal == 0.0); // 不好被廓。
if((fTestVal >= -EPSINON) && (fTestVal <= EPSINON)); // 推薦。EPSINON 為定義好的精度萝玷。在該范圍內(nèi)則認(rèn)為為零值
12.3 指針變量與“零值”進(jìn)行比較
if(p == 0); // 盡管 NULL 值為0嫁乘,容易引起 p 是整型的誤會。
if(p); // 容易引起 p 是 bool 型的誤會
if(NULL == p); // 推薦球碉。且 NULL 要寫在左值避免 p = NULL; 的錯(cuò)誤賦值蜓斧。
12.4 else 到底與哪個(gè) if 配對呢?
if(0 == x)
if(0 == y) error();
else {
//program code
} // 這段代碼容易引起誤會
- C 語言有這樣的規(guī)定:else始終與同一括號內(nèi)最近的未匹配的 if 語句結(jié)合。但是任何時(shí)候都不要偷懶睁冬。該寫花括號都要寫上挎春。
for (initialization; condition; update)
{
// 推薦風(fēng)格
}
for(initialization; condition; update){
// 不推薦風(fēng)格
}
12.5 if 語句后面的分號
- 如果出現(xiàn)以下代碼看疙,fun() 函數(shù)無論如何都會被調(diào)用:
if(NULL != p);
fun();
- 建議在真正需要用空語句時(shí)寫成這樣:
NULL;
- 13. switch case 關(guān)鍵字 -
- if、else 一般表示兩個(gè)分支或是嵌套表示少量的分支直奋,如果分支很多的話能庆,用 switch 和 case 組合更好
- 每個(gè) case 語句的結(jié)尾絕對不要忘了加 break,否則將導(dǎo)致多個(gè)分支重疊(除非有意使多個(gè)分支重疊)。
- 最后必須使用 default 分支脚线。即使程序真的不需要 default 處理搁胆,也應(yīng)該保留語句。這樣做并非畫蛇添足邮绿,可以避免讓人誤以為你忘了 default 處理渠旁。
13.1 case 關(guān)鍵字后面的值的要求
- case 后面只能是整型或字符型的常量或常量表達(dá)式
13.2 case語句的排列順序
- 按字母或數(shù)字順序排列各條 case 語句。
- 把正常情況放在前面,而把異常情況放在后面船逮。
- 按執(zhí)行頻率排列 case 語句顾腊。
13.3 使用 case 語句的其他注意事項(xiàng)
- 簡化每種情況對應(yīng)的操作。case 語句后面的代碼越精煉,case 語句的結(jié)
果就會越清晰。 - 不要為了使用 case 語句而刻意制造一個(gè)變量吉殃。
- 把 default 子句只用于檢查真正的默認(rèn)情況。
- 14. goto 關(guān)鍵字 -
- 一般來說,編碼的水平與 goto 語句使用的次數(shù)成反比伪煤。很多 C 語言編程書及其作者都主張禁用 goto 語句
struct student *p = NULL;
...
goto state;
p = (struct student *)malloc(...); // 被 goto 跳過,沒有初始化
...
state: // 使用 p 指向的內(nèi)存里的值的代碼?
- 循環(huán)分支 -
- 15. do while for 關(guān)鍵字 -
- C 語言中循環(huán)語句有三種:while 循環(huán)、do-while 循環(huán)凛辣、for 循環(huán)抱既。
- 死循環(huán)當(dāng)然有用,操作系統(tǒng)的整個(gè)進(jìn)程就是死循環(huán)扁誓,直到遇到關(guān)機(jī)指令防泵。
15.1 break 與 continue 的區(qū)別
- break 用來終止本層循環(huán)。
- continue 用來終止本次(本輪)循環(huán)蝗敢。
15.2 循環(huán)語句的注意點(diǎn)
- 在多重循環(huán)中,如果有可能,應(yīng)當(dāng)將最長的循環(huán)放在最內(nèi)層,最短的循環(huán)放在最外層,以減少 CPU 跨切循環(huán)層的次數(shù)捷泞。
- 建議 for 語句的循環(huán)控制變量的取值采用“半開半閉區(qū)間”寫法。
- 不能在 for 循環(huán)體內(nèi)修改循環(huán)變量,防止循環(huán)失控寿谴。
- 循環(huán)要盡可能的短,要使代碼清晰,一目了然锁右。
- 把循環(huán)嵌套控制在 3 層以內(nèi)。
- 其他 -
- 16. sizeof -- 最冤枉的關(guān)鍵字 -
很多人都認(rèn)為 sizeof 是函數(shù)讶泰,至少我第一次學(xué) C 語言的時(shí)候是這么認(rèn)為的咏瑟。然而事實(shí)呢? sizeof 是關(guān)鍵字痪署,常年被人誤認(rèn)為函數(shù)的關(guān)鍵字码泞。
sizeof 在計(jì)算變量所占空間大小時(shí),括號可以省略,而計(jì)算類型(模子)大小時(shí)不能省略。
一般情況下,sizeof 關(guān)鍵字后盡可能加上括號,繼續(xù)裝作函數(shù)狼犯。
sizeof(int); // 正確
sizeof int; // 錯(cuò)誤
int a[10];
sizeof a; // 正確
sizeof(a); // 正確
- 17. typedef -- 偉大的縫紉師 -
17.1 歷史的誤會----也許應(yīng)該是 typerename
- type 是數(shù)據(jù)類型的意思余寥,def(ine)是定義的意思领铐,合起來就是定義數(shù)據(jù)類型。然而事實(shí)并不是這樣宋舷,typedef 的真正意思是給一個(gè)已經(jīng)存在的數(shù)據(jù)類型(注意:是類型不是變量)取一個(gè)別名绪撵,而非定義一個(gè)新的數(shù)據(jù)類型。
typedef struct student {
//code
} Stu_st, *Stu_pst;
- 這時(shí)候祝蝠,下方的定義中(1)和(2)沒有區(qū)別莲兢,(3)、(4)和(5)沒有區(qū)別续膳。
struct student stu1; // (1)
Stu_st stu1; // (2)
struct student *stu2; // (3)
Stu_pst stu2; // (4)
Stu_st *stu2; // (5)
17.2 typedef 與#define 的區(qū)別
#define INT32 int
unsigned INT32 i = 10; // 正確
typedef int INT32;
unsigned INT32 j = 10; // 錯(cuò)誤
從這段代碼可以看出 typedef 取的別名不支持這種類型擴(kuò)展。
#define PCHAR char*
PCHAR p3,p4; // 等價(jià)于 char *p3;char p4;
typedef char* pchar;
pchar p1,p2; // 等價(jià)于 char *p1;char *p2;
從這段代碼又可以看出 #define 僅僅是簡單的替換收班,并無法代表一個(gè)數(shù)據(jù)類型坟岔。
- 18. volatile -- 最易變的關(guān)鍵字 -
- volatile 是易變的、不穩(wěn)定的意思摔桦,和 const 一樣是一種類型修飾符社付,用它修飾的變量表示可以被某些編譯器未知的因素更改,比如操作系統(tǒng)邻耕、硬件或者其它線程等鸥咖。遇到這個(gè)關(guān)鍵字聲明的變量,編譯器對訪問該變量的代碼就不再進(jìn)行優(yōu)化,從而可以 供對特殊地址的穩(wěn)定訪問。
18.1 編譯器優(yōu)化
int i=10;
int j = i; // (1)語句
int k = i; // (2)語句
- 編譯器在編譯時(shí)會對代碼進(jìn)行優(yōu)化兄世。而因?yàn)樵?1)啼辣、(2)兩條語句中 i 沒有被用作左值,這時(shí)候編譯器認(rèn)為 i 的值沒有發(fā)生改變御滩,所以在(1)語句時(shí)從內(nèi)存中取出 i 的值賦給 j 之后鸥拧,這個(gè)值并沒有被丟掉,而是在(2)語句時(shí)繼續(xù)用這個(gè)值給 k 賦值削解。編譯器不會生成出匯編代碼重新從內(nèi)存里取 i 的值,這樣提高了效率富弦。但要注意:(1)、(2)語句之間 i 沒有被用作左值才行氛驮。
18.2 volatile 關(guān)鍵字防止編譯器優(yōu)化
volatile int i=10;
int j = i; // (3)語句
int k = i; // (4)語句
- 如果將之前的代碼改成上面的樣子的話腕柜,volatile 關(guān)鍵字會告訴編譯器 i 是隨時(shí)可能發(fā)生變化的,每次使用它的時(shí)候必須從內(nèi)存中取出 i的值矫废,因而編譯器生成的匯編代碼會重新從 i 的地址處讀取數(shù)據(jù)放在 k 中盏缤。
- 19. return 關(guān)鍵字 -
- return 用來終止一個(gè)函數(shù)并返回其后面跟著的值。
- return 語句不可返回指向“棧內(nèi)存”的“指針”,因?yàn)樵搩?nèi)存在函數(shù)體結(jié)束時(shí)被自動銷毀磷脯。
- 關(guān)于 int main 中該不該出現(xiàn) return 0; 又為什么是這樣蛾找,我在我的博客園中如是寫道:
附錄:C 語言標(biāo)準(zhǔn)定義的 32 個(gè)關(guān)鍵字
關(guān)鍵字 | 意 義 |
---|---|
auto | 聲明自動變量,缺省時(shí)編譯器一般默認(rèn)為 auto |
int | 聲明整型變量 |
double | 聲明雙精度變量 |
long | 聲明長整型變量 |
char | 聲明字符型變量 |
float | 聲明浮點(diǎn)型變量 |
short | 聲明短整型變量 |
signed | 聲明有符號類型變量 |
unsigned | 聲明無符號類型變量 |
struct | 聲明結(jié)構(gòu)體變量 |
union | 聲明聯(lián)合數(shù)據(jù)類型 |
enum | 聲明枚舉類型 |
static | 聲明靜態(tài)變量 |
switch | 用于開關(guān)語句 |
case | 開關(guān)語句分支 |
default | 開關(guān)語句中的“其他”分支 |
break | 跳出當(dāng)前循環(huán) |
register | 聲明寄存器變量 |
const | 聲明只讀變量 |
volatile | 說明變量在程序執(zhí)行中可被隱含地改變 |
typedef | 用以給數(shù)據(jù)類型取別名(當(dāng)然還有其他作用) |
extern | 聲明變量是在其他文件正聲明(也可以看做是引用變量) |
return | 子程序返回語句(可以帶參數(shù),也可不帶參數(shù)) |
void | 聲明函數(shù)無返回值或無參數(shù),聲明空類型指針 |
continue | 結(jié)束當(dāng)前循環(huán),開始下一輪循環(huán) |
do | 循環(huán)語句的循環(huán)體 |
while | 循環(huán)語句的循環(huán)條件 |
if | 條件語句 |
else | 條件語句否定分支(與 if 連用) |
for | 一種循環(huán)語句(可意會不可言傳) |
goto | 無條件跳轉(zhuǎn)語句 |
sizeof | 計(jì)算對象所占內(nèi)存空間大小 |
寫在最后
這篇文章靈感和素材均來源自《C 語言深度解剖》這本書赵誓,感謝作者對 C 語言的獨(dú)特見解打毛,如有需要柿赊,歡迎購買實(shí)體書籍支持作者。
- Hello幻枉,我是韓亦樂碰声,現(xiàn)任本科軟工男一枚。軟件工程專業(yè)的一路學(xué)習(xí)中熬甫,我有很多感悟胰挑,也享受持續(xù)分享的過程。如果想了解更多或能及時(shí)收到我的最新文章椿肩,歡迎訂閱我的個(gè)人微信號:韓亦樂瞻颂。我的簡書個(gè)人主頁中,有我的訂閱號二維碼和 Github 主頁地址郑象;我的知乎主頁 中也會堅(jiān)持產(chǎn)出贡这,歡迎關(guān)注。
- 本文內(nèi)部編號經(jīng)由我的 Github 相關(guān)倉庫統(tǒng)一管理厂榛;本文可能發(fā)布在多個(gè)平臺但僅在上述倉庫中長期維護(hù)盖矫;本文同時(shí)采用【知識共享署名-非商業(yè)性使用-禁止演繹 4.0 國際許可協(xié)議】進(jìn)行許可。