C语言 —— 关键字(C语言标准定义的32个关键字:auto、register、static、sizeof、signed、unsigned 、break 、 continue 、void)
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 條件語句否定分支(與 if 連用)
for 一種循環語句(可意會不可言傳)
goto 無條件跳轉語句
sizeof 計算對象所占內存空間大小
?
1.1,最寬恒大量的關鍵字----auto
auto:它很寬恒大量的,你就當它不存在吧。編譯器在默認的缺省情況下,所有變量
都是 auto 的。
1.2,最快的關鍵字---- register
register:這個關鍵字請求編譯器盡可能的將變量存在 CPU 內部寄存器中而不是通過內
存尋址訪問以提高效率。注意是盡可能,不是絕對。你想想,一個 CPU 的寄存器也就那么
幾個或幾十個,你要是定義了很多很多 register 變量,它累死也可能不能全部把這些變量放
入寄存器吧,輪也可能輪不到你。
使用 register 修飾符的注意點:雖然寄存器的速度非常快,但是使用 register 修飾符也有些限制的: register 變量必須是
能被 CPU 寄存器所接受的類型。意味著 register 變量必須是一個單個的值,并且其長度應小
于或等于整型的長度。 而且 register 變量可能不存放在內存中, 所以不能用取址運算符“ &”
來獲取 register 變量的地址。
1.3,最名不符實的關鍵字----static
不要誤以為關鍵字 static 很安靜,其實它一點也不安靜。這個關鍵字在 C 語言里主要有
兩個作用, C++對它進行了擴展
1.3.1,修飾變量
第一個作用:修飾變量。變量又分為局部和全局變量,但它們都存在內存的靜態區。
靜態全局變量,作用域僅限于變量被定義的文件中,其他文件即使用 extern 聲明也沒法
使用他。準確地說作用域是從定義之處開始,到文件結尾處結束,在定義之處前面的那些
代碼行也不能使用它。想要使用就得在前面再加 extern ***。惡心吧?要想不惡心,很簡單,
直接在文件頂端定義不就得了。
靜態局部變量,在函數體里面定義的,就只能在這個函數里用了,同一個文檔中的其他
函數也用不了。由于被 static 修飾的變量總是存在內存的靜態區,所以即使這個函數運行結
束,這個靜態變量的值還是不會被銷毀,函數下次使用時仍然能用到這個值。
static int j;
void fun1( void)
{
static inti = 0;
i ++;
}
void fun2( void)
{
j = 0;
j++;
}
intmain()
{
for(k=0; k<10; k++)
{
fun1();
fun2();
}
return 0;
}
i 和 j 的值分別是什么,為什么?(i會從1累加到10,就)
1.3.2,修飾函數
第二個作用:修飾函數。函數前加 static 使得函數成為靜態函數。但此處“static”的含義
不是指存儲方式,而是指對函數的作用域僅局限于本文件(所以又稱內部函數)。使用內部函
數的好處是:不同的人編寫不同的函數時,不用擔心自己定義的函數,是否會與其它文件
中的函數同名。
關鍵字 static 有著不尋常的歷史。起初,在 C 中引入關鍵字 static 是為了表示退出一個
塊后仍然存在的局部變量。隨后, static 在 C 中有了第二種含義:用來表示不能被其它文件
訪問的全局變量和函數。為了避免引入新的關鍵字,所以仍使用 static 關鍵字來表示這第二
種含義。
當然, C++里對 static 賦予了第三個作用,這里先不討論,有興趣的可以找相關資料研
究。
1.4,基本數據類型----short、int、 long、char、float、double
C 語言包含的數據類型如下圖所示:
?
?一般來說習慣上用 n,m,i,j,k 等表示 int 類型的變量; c, ch 等表示字符類型變量; a 等表
示數組; p 等表示指針。當然這僅僅是一般習慣,除了 i,j,k 等可以用來表示循環變量外,別
的字符變量名盡量不要使用。
1.5,最冤枉的關鍵字----sizeof
sizeof 是關鍵字不是函數,其實就算不知道它是否為 32 個關鍵字之一時,我們也可以
借助編譯器確定它的身份。看下面的例子:
int i=0;
A),sizeof(int); B), sizeof(i); C), sizeof int; D), sizeof i;
毫無疑問, 32 位系統下 A), B)的值為 4。那 C)的呢? D)的呢?
在 32 位系統下,通過 Visual C++6.0 或任意一編譯器調試,我們發現 D)的結果也為 4。
咦? sizeof 后面的括號呢?沒有括號居然也行,那想想,函數名后面沒有括號行嗎?由此輕
易得出 sizeof 絕非函數。
好,再看 C)。編譯器怎么怎么提示出錯呢?不是說 sizeof 是個關鍵字,其后面的括號
可以沒有么?那你想想 sizeof int 表示什么啊? int 前面加一個關鍵字?類型擴展?明顯不
正確,我們可以在 int 前加 unsigned, const 等關鍵字但不能加 sizeof。好,記住: sizeof 在
計算變量所占空間大小時,括號可以省略,而計算類型(模子)大小時不能省略。一般情況下,
咱也別偷這個懶,乖乖的寫上括號,繼續裝作一個“函數”,做一個“披著函數皮的關鍵字”。
做我的關鍵字,讓人家認為是函數去吧。
1.6,signed、unsigned 關鍵字
我們知道計算機底層只認識 0、 1.任何數據到了底層都會變計算轉換成 0、 1.那負數怎么
存儲呢?肯定這個“ -”號是無法存入內存的,怎么辦?很好辦,做個標記。把基本數據類
型的最高位騰出來,用來存符號,同時約定如下:最高位如果是 1,表明這個數是負數,其
值為除最高位以外的剩余位的值添上這個“ -”號;如果最高位是 0,表明這個數是正數,
其值為除最高位以外的剩余位的值。
1.7 break 與 continue 的區別
break 關鍵字很重要,表示終止本層循環。現在這個例子只有一層循環,當代碼執行到
break 時,循環便終止。
如果把 break 換成 continue 會是什么樣子呢? continue 表示終止本次(本輪) 循環。當
代碼執行到 continue 時,本輪循環終止,進入下一輪循環。
while( 1)也有寫成 while(true) 或者 while(1==1) 或者 while((bool) 1)等形式的,效果一
樣。
do-while 循環:先執行 do 后面的代碼,然后再判斷 while 后面括號里的值,如果為真,
循環開始;否則,循環不開始。其用法與 while 循環沒有區別,但相對較少用。
for 循環: for 循環可以很容易的控制循環次數,多用于事先知道循環次數的情況下。
1.8,void 關鍵字
void 有什么好講的呢?如果你認為沒有,那就沒有;但如果你認為有,那就真的有。有點像“色即是空,空即是色”。
void 真正發揮的作用在于:
(1) 對函數返回的限定;? (2) 對函數參數的限定
眾所周知, 如果指針 p1 和 p2 的類型相同, 那么我們可以直接在 p1 和 p2 間互相賦值;
如果 p1 和 p2 指向不同的數據類型,則必須使用強制類型轉換運算符把賦值運算符右邊的
指針類型轉換為左邊指針的類型。
例如:
float *p1;
int *p2;
p1 = p2;
其中 p1 = p2 語句會編譯出錯,提示“'=' : cannot convertfrom 'int *' to 'float *'”,必須改為:
p1 = (float *)p2;
而 void *則不同,任何類型的指針都可以直接賦值給它,無需進行強制類型轉換:
void *p1;
int *p2;
p1 = p2;
但這并不意味著, void *也可以無需強制類型轉換地賦給其它類型的指針。因為“空類型”可
以包容“有類型”,而“有類型”則不能包容“空類型”。比如,我們可以說“男人和女人都是人”,
但不能說“人是男人”或者“人是女人”。下面的語句編譯出錯:
void *p1;
int *p2;
p2 = p1;
提示“'=' : cannot convert from 'void *' to 'int *'”。
void 修飾函數返回值和參數
【規則 1-33】如果函數沒有返回值,那么應聲明為 void 類型
在 C 語言中,凡不加返回值類型限定的函數,就會被編譯器作為返回整型值處理。但
是許多程序員卻誤以為其為 void 類型。例如:
add ( int a, int b )
{
return a + b;
}
int main(int argc, char* argv[]) //甚至很多人以為 main 函數無返回值
//或是為 void 型的
{
printf ( "2 + 3 = %d", add ( 2, 3) );
}
程序運行的結果為輸出: 2 + 3 = 5
這說明不加返回值說明的函數的確為 int 函數。
因此,為了避免混亂,我們在編寫 C 程序時,對于任何函數都必須一個不漏地指定其
類型。如果函數沒有返回值,一定要聲明為 void 類型。這既是程序良好可讀性的需要,也
是編程規范性的要求。另外,加上 void 類型聲明后,也可以發揮代碼的“自注釋”作用。所
謂的代碼的“自注釋”即代碼能自己注釋自己。
【規則 1-34】如果函數無參數,那么應聲明其參數為 void
在 C++語言中聲明一個這樣的函數:
int function(void)
{
return 1;
}
則進行下面的調用是不合法的: function(2);
因為在 C++中,函數參數為 void 的意思是這個函數不接受任何參數。
但是在 Turbo C 2.0 中編譯:
#include "stdio.h"
fun()
{
return 1;
}
main()
{
printf("%d",fun(2));
getchar();
更多免費資源:www.fishc.com
}
編譯正確且輸出 1,這說明,在 C 語言中,可以給無參數的函數傳送任意類型的參數,
但是在 C++編譯器中編譯同樣的代碼則會出錯。在 C++中,不能向無參數的函數傳送任何
參數,出錯提示“'fun' : function does not take 1 parameters”。
所以,無論在 C 還是 C++中,若函數不接受任何參數,一定要指明參數為 void
void 指針
【規則 1-35】千萬小心又小心使用 void 指針類型。
按照 ANSI(American National Standards Institute)標準,不能對 void 指針進行算法操作,
即下列操作都是不合法的:
void * pvoid;
pvoid++; //ANSI:錯誤
pvoid += 1; //ANSI:錯誤
ANSI 標準之所以這樣認定,是因為它堅持:進行算法操作的指針必須是確定知道其指
向數據類型大小的。也就是說必須知道內存目的地址的確切值。
例如:
int *pint;
pint++; //ANSI:正確
但是大名鼎鼎的 GNU(GNU's Not Unix 的遞歸縮寫)則不這么認定,它指定 void *的算法
操作與 char *一致。因此下列語句在 GNU 編譯器中皆正確:
pvoid++; //GNU:正確
pvoid += 1; //GNU:正確
在實際的程序設計中,為符合 ANSI 標準,并提高程序的可移植性,我們可以這樣編寫
實現同樣功能的代碼:
void * pvoid;
(char *)pvoid++; //ANSI:正確; GNU:正確
(char *)pvoid += 1; //ANSI:錯誤; GNU:正確
GNU 和 ANSI 還有一些區別,總體而言, GNU 較 ANSI 更“開放”,提供了對更多語法
的支持。但是我們在真實設計時,還是應該盡可能地符合 ANSI 標準。
【規則 1-36】如果函數的參數可以是任意類型指針,那么應聲明其參數為 void *。
典型的如內存操作函數 memcpy 和 memset 的函數原型分別為:
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );
這樣,任何類型的指針都可以傳入 memcpy 和 memset 中,這也真實地體現了內存操作
函數的意義, 因為它操作的對象僅僅是一片內存, 而不論這片內存是什么類型。如果 memcpy
和 memset 的參數類型不是 void *,而是 char *,那才叫真的奇怪了!這樣的 memcpy 和 memset
明顯不是一個“純粹的,脫離低級趣味的”函數!
下面的代碼執行正確:
例子: memset 接受任意類型指針
int IntArray_a[100];
memset (IntArray_a, 0, 100*sizeof(int) ); //將 IntArray_a 清 0
例子: memcpy 接受任意類型指針
int destIntArray_a[100], srcintarray_a[100];
//將 srcintarray_a 拷貝給 destIntArray_a
memcpy (destIntArray_a, srcintarray_a, 100*sizeof(int) );
有趣的是, memcpy 和 memset 函數返回的也是 void *類型,標準庫函數的編寫者都不是一
般人。
1.9,void 關鍵字
return 用來終止一個函數并返回其后面跟著的值。
return (Val); //此括號可以省略。但一般不省略,尤其在返回一個表達式的值時。
return 可以返回些什么東西呢?看下面例子:
char * Func(void)
{
char str[30];
…
return str;
}
str 屬于局部變量,位于棧內存中,在 Func 結束的時候被釋放,所以返回 str 將導致錯誤。
2.0,const?關鍵字
2.0.1,修飾一般變量
一般常量是指簡單類型的只讀變量。這種只讀變量在定義時,修飾符 const 可以用在類
型說明符前,也可以用在類型說明符后。例如:
int const i=2; 或 const int i=2;
2.0.2,修飾數組
定義或說明一個只讀數組可采用如下格式:
int const a[5]={1, 2, 3, 4, 5};或
const int a[5]={1, 2, 3, 4, 5};
2.0.3,修飾指針
先忽略類型名(編譯器解析的時候也是忽略類型名),我們看 const 離哪個近。“近水樓
臺先得月”,離誰近就修飾誰。
const int *p; //const 修飾*p,p 是指針, *p 是指針指向的對象,不可變
int const *p; //const 修飾*p,p 是指針, *p 是指針指向的對象,不可變
int *const p; //const 修飾 p, p 不可變, p 指向的對象可變
const int *const p; //前一個 const 修飾*p,后一個 const 修飾 p,指針 p 和 p 指向的對象
都不可變
2.0.4修飾函數的參數
const 修飾符也可以修飾函數的參數,當不希望這個參數值被函數體內意外改變時使
用。例如:
void Fun(const int i);
告訴編譯器 i 在函數體中的不能改變,從而防止了使用者的一些無意的或錯誤的修改。
2.0.5修飾函數的返回值
const 修飾符也可以修飾函數的返回值,返回值不可被改變。例如:
const int Fun (void);
在另一連接文件中引用 const 只讀變量:
extern const int i; //正確的聲明
extern const int j=10; //錯誤!只讀變量的值不能改變。
參考書籍《C語言深度剖析》
總結
以上是生活随笔為你收集整理的C语言 —— 关键字(C语言标准定义的32个关键字:auto、register、static、sizeof、signed、unsigned 、break 、 continue 、void)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Nginx —— 用HTTP proxy
- 下一篇: 计算机原理与基础 —— 进制之间