C 語言 32 個(gè)關(guān)鍵字 GET 進(jìn)行曲

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)存打交道东帅。

為什么寄存器比內(nèi)存快压固?

CPU Registers 即為寄存器

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ǔ)碼的知識都在我的博客園里寫過砰左,期待之后整理到簡書中來。

「C語言」原碼反碼補(bǔ)碼與位運(yùn)算

- 數(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)鍵字”上立膛。

「C語言」數(shù)據(jù)類型及混合運(yùn)算與類型轉(zhuǎn)換

7.2 變量的命名規(guī)則

  • 命名和緩存失效是計(jì)算機(jī)科學(xué)面臨的最難的兩件事。其中符合規(guī)范的變量命名可以直觀地看出代碼的邏輯性梯码,具體命名規(guī)則也同樣加入自己的博客園文章地址宝泵,期待之后整理到簡書中來。

「C語言」常量和變量的表示轩娶、應(yīng)用和變量命名規(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語言」int main還是void main?

附錄: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í)體書籍支持作者。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末击奶,一起剝皮案震驚了整個(gè)濱河市辈双,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌柜砾,老刑警劉巖湃望,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異痰驱,居然都是意外死亡喜爷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門萄唇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來檩帐,“玉大人,你說我怎么就攤上這事另萤∨让埽” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵四敞,是天一觀的道長泛源。 經(jīng)常有香客問我,道長忿危,這世上最難降的妖魔是什么达箍? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮铺厨,結(jié)果婚禮上缎玫,老公的妹妹穿的比我還像新娘硬纤。我一直安慰自己,他們只是感情好赃磨,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布筝家。 她就那樣靜靜地躺著,像睡著了一般邻辉。 火紅的嫁衣襯著肌膚如雪溪王。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天值骇,我揣著相機(jī)與錄音莹菱,去河邊找鬼。 笑死吱瘩,一個(gè)胖子當(dāng)著我的面吹牛芒珠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播搅裙,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼裹芝!你這毒婦竟也來了部逮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤嫂易,失蹤者是張志新(化名)和其女友劉穎兄朋,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體怜械,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡颅和,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了缕允。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片峡扩。...
    茶點(diǎn)故事閱讀 40,615評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖障本,靈堂內(nèi)的尸體忽然破棺而出教届,到底是詐尸還是另有隱情,我是刑警寧澤驾霜,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布案训,位于F島的核電站,受9級特大地震影響粪糙,放射性物質(zhì)發(fā)生泄漏强霎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一蓉冈、第九天 我趴在偏房一處隱蔽的房頂上張望城舞。 院中可真熱鬧轩触,春花似錦、人聲如沸椿争。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秦踪。三九已至褐捻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間椅邓,已是汗流浹背柠逞。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留景馁,地道東北人板壮。 一個(gè)月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像合住,于是被迫代替她去往敵國和親绰精。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 注:這是第三遍讀《C語言深度解剖》透葛,想想好像自從大學(xué)開始就沒讀完過幾本書笨使,其中譚浩強(qiáng)的那本《C語言程序設(shè)計(jì)(第四版...
    HavenXie閱讀 1,736評論 1 6
  • 首先硫椰,為什么要學(xué)好英語? 學(xué)好英語萨蚕,可以接觸到全世界的智慧和經(jīng)驗(yàn)靶草。無論從事哪個(gè)行業(yè),全球互聯(lián)網(wǎng)上大多數(shù)的資料都是以...
    王勛_CLASS通閱讀 1,028評論 3 7
  • 題記∶If you're not drinkin' then you're not playin'岳遥,若你不醉奕翔,勢必...
    LionHeart_LH閱讀 508評論 0 1
  • 網(wǎng)上新興起一種新東西叫‘’社群‘’,十幾個(gè)人組成學(xué)習(xí)小組浩蓉,或讀書糠悯,或運(yùn)動,在相互督促妻往,相互鼓勵(lì)互艾,相互指導(dǎo)中完成...
    明子zero閱讀 518評論 0 0