深入理解C之關鍵字
由於最近一段時間一直在忙於WEB的前端開發,很久都沒有寫過C方面的程式,感覺很陌生了一樣,真的是一天不練,都被拉到千里之外,趁現在正好手上有一個關於C方面的專案,特地的總結了一下C語言關鍵字的使用及注意事項。
C語言標準定義的32個關鍵字
auto | 宣告自動變數,預設時編譯器一般預設為auto |
int | 宣告整理變數 |
double | 宣告雙精度變數 |
long | 宣告長整型變數 |
char | 宣告字元型變數 |
float | 宣告單精度浮點變數 |
short | 宣告短整型變數 |
signed | 宣告有符號型別變數 |
unsigned | 宣告無符號型別變數 |
struct | 宣告結構體變數 |
union | 宣告聯合資料型別 |
enum | 宣告列舉型別 |
static | 宣告靜態變數 |
switch | 用於開關語句 |
case | 開關語句分支 |
default | 開關語句的其它分支 |
break | 跳出當前迴圈 |
register | 宣告暫存器變數 |
const | 宣告只讀變數 |
volatile | 說明變數在程式執行中可被隱含地改變 |
typedef | 用以給資料型別取別名 |
extern | 宣告變數是在其他檔案中宣告(也可看作引用變數) |
return | 子程式返回語句(可以帶引數,也可以不帶引數) |
void | 宣告函式無返回值或無引數、宣告空型別指標 |
continue | 結束當前迴圈,開始下一輪迴圈 |
do | 迴圈語句的迴圈條件 |
while | 迴圈語句的迴圈條件 |
if | 條件語句 |
else | 條件語句否定分支 |
for | 一種迴圈語句(可意會不可言傳) |
goto | 無條件跳轉語句 |
sizeof | 計算物件所佔記憶體空間大小 |
下面挑選一些比較重要,容易將用法和概念混淆的關鍵字進行總結,以下內容是本人查詢資料進行整理的。
一、Const
const從字面是恆定不變的意思,也翻譯成常量和常數,可能正因為這一點,很多人都認為被const修飾的值是常量,這不精確,精確來說應該是隻讀變數,其值在編譯時不能被使用。
1、Const作用
(1)可以定義定義const常量:const int MAX = 100;
(2)便於進行型別檢查:const常量有資料型別,而巨集常量沒有資料型別,
(3)可以保護被修飾的東西:防止意外的修改,增強程式的健壯性。
(4)可以很方便的進行引數的調整:同巨集定義一樣,可以做到不變則已,一變都變。
(5)提高了效率:編譯器通常不為普通const常量分配儲存空間,而是將它們儲存在符號表中。
示例程式:
#define M 3 //巨集常量
const int N = 5; //此時並未將N放入記憶體中
.......
int i = N; //此時為N分配記憶體,以後不再分配
int I = M; //預編譯期間進行巨集替換,分配記憶體
int j = N; //沒有記憶體分配
int J = M; //再進行巨集替換,又一次分配記憶體
2、Const的變數和指標使用
(1)定義常量:const修飾型別的變數value是不可變的,以下兩種定義形式在本質上是一樣的。
int const ValueName = value;
const int ValueName = value;
(2)指標使用const
a. 指標本身是常量不可變
char* const pContent;
b. 指標所指向的內容是常量不可變
char const* pContent;
c. 兩者都不可變
const char* const pContent;
d. 區別方法
在*中間畫一條線,如const在*左邊,則const修飾指向的變數,如cosnt在*右邊,const修飾指標本身。
3、函式中使用Const
(1)const修飾函式引數
a. 傳遞過來的引數在函式內不可變(無意義,因為Var本身就是形參)
void function(const int Var);
b. 引數指標所指內容為常量不可變
void function(const char* Var);
c. 引數指標本身不可變(無意義,因為char * Var也是形參)
void function(char* const Var);
d. 引數為引用,為了增加效率同時防止修改,引數不可變--C++特性
void function(const Class & Var);
(2)const修飾函式返回值
const修飾函式返回值其實用的並不是很多,它的含義和const修飾普通變數以及指標的含義基本相同。
a. const int fun1() ; //這個其實無意義,因為引數返回本身就是賦值
b. const int * fun2(); //呼叫時使用const int *pValue = fun2();
//我們可以把fun2()看成一個變數,即指標內容不可變
c. int * const fun3(); //呼叫時使用int* const pValue = fun3();
//我們可以把fun3()看成一個變數,即指標本身不可變
二、Static
從字面意思是靜止的、不變的,下面主要從作用域、儲存域方面進行講解。
1、修飾變數
修飾變數又分為修飾區域性變數和修飾全域性變數。
(1)修飾區域性變數
作用域:只限在本檔案使用(又稱內部變數),外部檔案不能使用,準確的說,作用域是從定義之處開始,到檔案結束,定義之前的程式碼不能使用它。
儲存域:儲存在靜態區,同時在所處模組初次執行時進行初始化工作,且只初始化一次。
(2)修飾全域性變數
作用域:只限在本檔案使用,外部檔案不能使用。
儲存域:儲存在靜態區,如果不賦初值,編譯期會自動賦初值0或空字元。
(3)普通變數
作用域:區域性變數生存週期在模組執行時,執行結束就被立刻釋放,全域性變數在整個檔案和外部檔案(使用extern宣告)都可使用。
儲存域:區域性變數儲存在棧區,全域性變數儲存在靜態區。
示例程式一:
#include <stdio.h>
void staticAddVal()
{
static int a;
printf("a=%d ",a);
a ++;
}
int main()
{
staticAddVal(); <span style="color:#009900;">//第一次呼叫輸出a=0;</span>
staticAddVal(); <span style="color:#009900;">//第二次呼叫記憶了第一次退出的值,輸出a=1</span>
return 0;
}
示例程式二:
//file1.c
int varA = 1;
static int varB;
void funA(){}
.....
//file2.c
extern int varA; <span style="color:#009900;">//使用file1.cpp中定義的全域性變數</span>
extern int varB; <span style="color:#009900;">//錯誤!varB是static型別,無法在其它檔案中使用</span>
.....
int main()
{
....
}
2、修飾函式
修飾函式使得函式成為靜態函式,但此處的"static"的含義不是指儲存方式,而是指對函式的作用域僅侷限於本檔案(又稱內部函式),利用這一特性可以在不同的檔案中定義同名函式,而不必擔心命名衝突。
示例程式三:
//file1.c
void funA()
{
....
}
static void funB()
{
....
}
//file2.c
extern void funA(); <span style="color:#009900;">//使用file1.c中定義的函式</span>
extern void funB(); <span style="color:#009900;">//錯誤!無法使用file1.c檔案中的static函式</span>
.....
int main()
{
.....
}
三、Extern
修飾符extern用在變數或者函式的宣告前,用來說明此變數/函式是在別處定義過的,要在本檔案中引用。
注:定義的全域性變數或函式預設的是extern,具有外連性。
1、extern修飾變數/函式
示例程式一:
//file1.c
int iNum = 10;
int iVar = 9.9;
void funA(void)
{
.....
}
static void funB(void)
{
.....
}
//file2.c
extern int iNum; <span style="color:#009900;">//使用file1.c中的變數iNum</span><span style="color:#006600;"> </span>
extern double iVar; <span style="color:#009900;">//錯誤!型別不一樣</span>
extern void funA(void); <span style="color:#009900;">//呼叫file1.c中的函式funA</span>
extern void funB(void); <span style="color:#009900;">//錯誤!static修飾的函式具有隱藏性,不可外用</span>
.....
int main()
{
...
}
2、extern "C"的使用
在C++環境下使用C函式時,常常會出現編譯器無法找到obj模組中的C函式定義,從而導致連結失敗的情況。
示例程式二:
#ifdef __cplusplus
extern "C" {
#endif
/*...*/
#ifdef __cplusplus
}
#endif
四、Volatile
volatile是易變的、不穩定的意思,遇到這個關鍵字宣告的變數,編譯器對訪問該變數的程式碼就不再進行優化,從而可以提供對特殊地址的穩定訪問。
示例程式一:
int i = 10;
int j = i; //①語句
int k = i; //②語句
此時編譯器對程式碼進行優化,這是因為①②語句中,i沒有被賦值,這是編譯器認為i的值沒有發生改變,所以在①語句時從記憶體中取出i的值賦給j之後,這個值並沒有被丟掉,而是在②語句時繼續賦值給k。
示例程式二:
volatile int i = 10;
int j = i; //①語句
int k = i; //②語句
volatile關鍵字告訴編譯器,i隨時可能發生變化的,每次使用他的時候必須從記憶體中取出i的值,因而編譯器生存的彙編程式碼會重新從i的地址處讀取資料放在k中。