1. 程式人生 > >C語言關鍵字解析

C語言關鍵字解析

C語言關鍵字解析

C語言關鍵字有32個,如表1所示。雖然簡單,但還是讓一些初學者犯錯,譬如sizeof,好多初學者都認為是函式,其中包括我的一些同學,他們學過有好多年了,如此看來,有時我們追求高深的內容,往往會忽略基礎的簡單的內容!

1 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.告訴編譯器,這個變數或者函式,我已經定義了(開闢空間了),但是在別的地方,我先說明一下,免得編譯器報錯。當然,宣告可以多次出現。

2.告訴編譯器,這個變數名或者物件名,我先預定了,其他地方不可以用了。和在飯館吃飯(人多)要提前預約一樣的道理。

定義和宣告最本質的區別在於,宣告沒開闢空間,而定義則建立物件(變數)並開闢了空間。這是最重要的一點。

. autoregisterexternstatic,四種關鍵字

C語言說明變數的時,同時給出了兩個方面的資訊:資料型別和儲存類。C語言中提供了儲存說明符autoregisterexternstatic說明的四種儲存類別。

1.auto 是變數是C語言最常用的。編譯器在預設的預設情況下,所有變數都是auto的。對於函式的形參,也是auto型的。

2.extern語言中存在這樣的一種變數,在一個函式中合法出現的同時,又可以在其他的函式中合法出現,這就是外部變數。它的生命週期是整個程式的執行週期。

3.register,暫存器變數,其值存放在暫存器中,訪問速度快。有最快的關鍵字的稱呼。雖然暫存器的速度非常快,但是使用 register修飾符也有些限制的:register變數必須是能被 CPU暫存器所接受的型別。意味著 register變數必須是一個單個的值,並且其長度應小於或等於整型的長度。而且register變數可能不存放在記憶體中,所以不能用取址運算子&”來獲取 register變數的地址。

4.static 靜態變數,兩個作用。第一個作用:修飾變數,都存在記憶體的靜態區。

靜態區域性變數:出現在函式體內,生命週期是整個程式的執行過程,由於被 static修飾的變數總是存在記憶體的靜態區,即使該函式生命結束,其值不會被銷燬,同樣要修改該變數,就要到函式內部完成,所以用起來比較安全,起到資訊遮蔽的作用。

靜態全域性變數:出現在函式體外,作用域僅限於變數被定義的檔案中,其他檔案即使用 extern宣告也沒法使用他。

第二個作用,修飾函式,函式前加 static使得函式成為靜態函式。但此處“static”的含義不是指儲存方式,而是指對函式的作用域僅侷限於本檔案(所以又稱內部函式)。使用內部函式的好處是:不同的人編寫不同的函式時,不用擔心自己定義的函式,是否會與其它檔案中的函式同名。

.基本資料型別----shortint longcharfloatdouble

這些關鍵字都是基本的資料型別,每種型別佔據的記憶體空間不一樣,其實每種型別相當於一個模型,再通俗點就是一個模子。具體佔多少個位元組,可以用關鍵字sizeof去測一下。另外就就是儲存問題。不論是float還是double在儲存方式上都遵從IEEE的規範,float遵從的是IEEE R32.24 ,double 遵從的是R64.53
#include <stdio.h>
int main()
{
float a=999.999;
float b=0.005;
printf("%lf/n",a+b-1000.004);
return 0;
}
看看得到的結果並不是0,按數學計算本來應該是0,但由於浮點數的儲存有微小的誤差從而導致計算結果不是0
double m=3.3;
cout<<m;
你輸入3.3,再除錯監測m的值你會發現儲存的是3.2999999999999998,而不是3.3.這就是本來是3.3而經過儲存卻變的不是3.3.
對計算機來說,實數是不存在的東西。一般,計算機除了認識“整數”——這個整數和數學中的整數也不是一個東西。
還認識的一種數就是“浮點數”——和數學中的實數更是兩碼事。
三.最冤枉的關鍵字sizeof
經常被我們當成函式來使用,雖然造型很像函式,其實是關鍵字,
int i=0
A),sizeof(int) B)sizeof(i) C)sizeof int D)sizeof i
以上四種寫法都是正確的,結果為4.可以在VC6.0編譯器watch視窗下觀察,前兩種寫法很常見,但後面的也正確。從cd正確可以排除sizeof是函式的說法,當然我們在使用的時候還是加上括號,披著函式皮的關鍵字吧!
請看下面的例子:
struct Test
{int Num
char*Pc
short sDtate
char ch[2];
short S[4];
}*p;
那麼這個結構體的大小多少呢?他與共同體的區別很明顯,共同體所有成員變數都共用同一塊記憶體,而結構體每個元素都佔用相應地記憶體。
共同體的最大的成員所佔記憶體為共同體佔用記憶體。
int:佔4個位元組(32系統)。
char*pc4個:指標相當於地址,地址就是你當前作業系統的位數。如果是指標陣列即存放指標的陣列,佔用的空間是4*陣列的個數。
如果是陣列指標即指向陣列的指標,指標指向的是陣列的地址,佔用4個位元組。
short sDtate2
char ch[2]:2
short S[4]:2*4=8 short型陣列
所以一起:4+4+2+2+8=20位元組。VC下驗證是正確的,不要以為這樣就沒事了,其實還是有問題的:位元組對齊的問題。
struct S1
{
char c;
int i;
 };
S1 s1={'a',0xFFFFFFFF};
sizeof(s1)等於多少?char1個位元組,int4個位元組,那麼加起來就應該是5。這樣算對嗎?VC6中按預設設定得到的結果卻是為8
我們來好好琢磨一下sizeof的定義——sizeof的結果等於物件或者型別所佔的記憶體位元組數,好吧,那就讓我們來看看S1的記憶體分配情況:
以我的VC6.0為例,s1的地址為0x0012FF74,使用memory視窗觀察,其資料內容如下:
0012FF74: 61 CC CC CC FF FF FF FF
你會發現中間夾雜了3個位元組的CC?看看MSDN上的說明:
When applied to a structure type or variable, sizeof returns the actual size,which may include padding bytes inserted for alignment.
原來如此,這就是傳說中的位元組對齊啊!那麼為什麼需要位元組對齊?計算機組成原理教導我們這樣有助於加快計算機的取數速度,否則就得多花指令週期了。各個硬體平臺對儲存空間的處理上有很大的不同。一些平臺對某些特定型別的資料只能從某些特定地址開始存取。其他平臺可能沒有這種情況, 但是最常見的是如果不按照適合其平臺的要求對資料存放進行對齊,會在存取效率上帶來損失。這也是空間和時間的博弈

部分內容參考了陳正衝 《C語言深度解剖》。

還有這個網站上關於位元組對齊寫得不錯,可以看看!