溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C語言關(guān)鍵字(三)

發(fā)布時間:2020-08-10 08:54:19 來源:ITPUB博客 閱讀:171 作者:LinuxDevqqqqqq 欄目:編程語言

這篇文件繼續(xù)講解 C 語言關(guān)鍵字

想問大家一個問題,什么是聲明什么是定義?

舉個例子:

A)int i ;

B)extern int i ; ( 關(guān)于 extern ,后面解釋 )

哪個是定義?哪個是聲明?或者都是定義或者都是聲明?

什么是定義: 所謂的定義就是 ( 編譯器 ) 創(chuàng)建一個對象,為這個對象分配一塊內(nèi)存并給它取上一個名字,這個名字就是我們經(jīng)常所說的變量名或?qū)ο竺?。但注意,這個名字一旦和這塊內(nèi)存匹配起來,它們就同生共死,終生不離不棄。并且這塊內(nèi)存的位置也不能被改變。一個變量或?qū)ο笤谝欢ǖ膮^(qū)域內(nèi)(比如函數(shù)內(nèi),全局等)只能被定義一次,如果定義多次,編譯器會提示你重復(fù)定義同一個變量或?qū)ο蟆?

什么是聲明: 有兩重含義,如下:

第一重含義:告訴編譯器,這個名字已經(jīng)匹配到一塊內(nèi)存上了,(就比如你拿出結(jié)婚證告訴別人,我已經(jīng)和別的內(nèi)存塊結(jié)婚了,請不要再勾搭我了)。

第二重含義:告訴編譯器,我這個名字我先預(yù)定了,別的地方再也不能用它來作為變量名或?qū)ο竺?。(這個就有點(diǎn)耍賴,你拿著一個假的結(jié)婚證告訴別人,我已經(jīng)結(jié)婚了,但是實(shí)際上,你還沒有妹子,還沒有分配內(nèi)存空間)。

好,這樣一解釋,我們可以很清楚的判斷 :A) 是定義; B) 是聲明。

那他們的區(qū)別也很清晰了。記住, 定義聲明最重要的區(qū)別:定義創(chuàng)建了對象并為這個對象一塊內(nèi)存,而聲明的時候是沒有分配內(nèi)存空間的。

 

1 ,不需要記住的關(guān)鍵字 ----auto

 

auto :他太普通了,你就當(dāng)它不存在吧。編譯器在默認(rèn)的缺省情況下,所有變量

都是 auto  的。

 

2 ,最快的關(guān)鍵字 ---- register

 

register :這個關(guān)鍵字請求編譯器盡可能的將變量存在 CPU  內(nèi)部寄存器中而不是通過內(nèi)

存尋址訪問以提高效率。注意是盡可能,不是絕對。你想想,一個 CPU  的寄存器也就那么

幾個或幾十個,你要是定義了很多很多 register  變量,它累死也可能不能全部把這些變量放

入寄存器吧,輪也可能輪不到你。

 

2.1 ,皇帝( CPU )身邊的小太監(jiān) ---- 寄存器

cpu 類比成為一個皇帝,那 register 就是皇帝身邊的小太監(jiān)了,不知道大家見過太監(jiān)沒有,我們看各種宮斗劇的時候,太監(jiān)是唯命是從,只要皇帝叫做什么,太監(jiān)馬上就去做,速度之快令人瞠目結(jié)舌,也就是因?yàn)樗俣瓤?,所以皇帝才配有太監(jiān),而且不止有一個太監(jiān),太監(jiān)就像一個文件中轉(zhuǎn)站,把下面人的折子拿給皇帝批閱。

所以太監(jiān)的特點(diǎn)是

1 、響應(yīng)速度快

2 、數(shù)量少,只給皇帝工作

3 、價格貴

 

 

2.2 ,使用 register 修飾符的注意點(diǎn)

 

雖然寄存器的速度非???,但是使用 register  修飾符也有些限制的: register  變量必須是能被 CPU  寄存器所接受的類型。意味著 register  變量必須是一個單個的值,并且其長度應(yīng)小于或等于整型的長度。 而且 register  變量可能不存放在內(nèi)存中,所以不能用取址運(yùn)算符 “&” 來獲取 register  變量的地址。

3 、確定位置的關(guān)鍵字 ----static

3.1 、 static  修飾變量

修飾靜態(tài)全局變量:作用域僅限制于被定義的文件中,其他文件即使用 extern 聲明也沒有辦法使用,作用域從定義之處開始,到文件結(jié)尾處,在定義之前的代碼不能使用。本文件可以在之前加 extern  ,不過這樣還不如直接在頂端定義。

 

靜態(tài)全局變量:在函數(shù)體里面定義的,就只能在函數(shù)里面使用了,由于 static 定義的變量存在靜態(tài)區(qū),改函數(shù)執(zhí)行結(jié)束,變量的值還是存在,不會銷毀,下次該函數(shù)調(diào)用時, static 定義的變量值是上一次調(diào)用時候的值。

3.2 、 static 修飾函數(shù)

在函數(shù)前面加 static 表示函數(shù)成為靜態(tài)函數(shù),表示該函數(shù)的作用域僅限于定義處到文件結(jié)尾。如果全局函數(shù)有一個函數(shù)名字和靜態(tài)函數(shù)一樣的名字,編譯器不會報(bào)錯,使用本文件的靜態(tài)函數(shù)運(yùn)行。

#include <stdio.h>

 

static int j;

 

void func1 ( void )

{

      static int = ;

     i ++ ;

     printf( "i = %d\n" , i);

}

 

void func2 ( void )

{

     j  = ;

     j ++ ;

     printf( "j = %d\n" , j);

}

 

int main ( int argc,  char * argv[])

{

      int = ;

      for (k  = ; k < 10 ; k ++ )

     {

         func1();

         func2();

         printf( "\n" );

     }

      return ;

}

大家運(yùn)行上面代碼加深下對 static 的理解

 

4 、大喇叭關(guān)鍵字 ----extern

上面有一個例子已經(jīng)說到了 extern,extern 就像一個大喇叭一樣,他不分配內(nèi)存,就是不討老婆,但是總是跟別人說,誰誰娶媳婦了,這個標(biāo)識符就定義了,這個函數(shù)被定義了,如此如此,不過這個大喇叭非常有用,比如他可以跟編譯器說,這個家伙已經(jīng)討老婆了,你可以用他生孩子了,就不要再讓他二婚了。

既然 extern 不能給別人發(fā)結(jié)婚證,那么下面這個

extern int i = 10;

是否有問題?

不能發(fā)結(jié)婚證,就是不能分配內(nèi)儲存,沒有內(nèi)存怎么把 10 存下來?所以肯定是錯的。

 

5 、讓 cpu 最累的關(guān)鍵字 ----volitile

volitile 這個關(guān)鍵字讓 cpu 非常累,每次運(yùn)行到他的位置,都要去內(nèi)存重新確定他的值,在中斷的使用的變量最好用這個關(guān)鍵字修飾,因?yàn)橹袛嗟淖兞磕悴恢朗裁磿r候會被改變, volatile 的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設(shè)這個變量的值了。說白了就是不能讓 cpu 偷懶,所以說是類似老大 CPU 了。

 

6 、只能讀的關(guān)鍵字 ----const

const 可以理解為別人只能來讀我的值,不能改變我,有的人寫代碼加上這個就是擔(dān)心自己的值被改變,比如 const int i =5; 下一次, i =6; 這就是有問題的, 的值已經(jīng)確定了,就像 define 一樣( 不過 define 不是關(guān)鍵字 )。

/*************************************************************************

    > File Name: const.c

    > Author:           

    > Mail:             

    > Created Time: Mon 29 Oct 2018 02:33:19 PM CST

 ************************************************************************/

                        

#include <stdio.h>       

#define M 3             

const int = 5 ;        

                        

void main ( void )        

{                       

    printf( "%p\n" , & N);

     int = M;          

     int = N;          

    printf( "%p\n" , & N);                                                                                                

     int = M;          

     int = N;          

    printf( "%p %p %p %p\n" , & i, & j, & x, & y);

    printf( "%d %d %d %d\n" ,i,j,x,y);

}         

7 、不色不空的關(guān)鍵字 ----void

大家可以看看 void  void*  ,誰是色,誰是空呢? void  表示這個是空的,什么都沒有,比如 void i;  我們定義一個空的 i ,這就有問題了,這個 i 編譯器到底要不要給他分配空間呢?就是這樣的情況,編譯器報(bào)錯了,你搞什么飛機(jī)給我一個空的東西還想讓我給你討老婆。

但是 void  不一樣, void  * 表示所有類型的指針,這就是色啊,女人都想入非非。

說明: 既然提供了 void 的這兩種用法,就去運(yùn)用。即函數(shù)沒返回值就將其返回值類型寫為 void ,函數(shù)沒有形參就將其形參寫為 void 。不了解編譯器默認(rèn)操作時,不要依賴。即使了解其默認(rèn)操作,也別依賴,因?yàn)榭隙ㄓ腥瞬涣私獾模@樣別人就看不懂你的代碼了。

大家看看這個是否正確

add(int a,int b)

{

    return (a+b);

}

下面兩個函數(shù)就是用 void* 作為返回值

memcpy   

原型: extern void *memcpy(void *dest, void *src, unsigned int count);    

用法: #include    

功能:由 src 所指內(nèi)存區(qū)域復(fù)制 count 個字節(jié)到 dest 所指內(nèi)存區(qū)域。   

說明: src dest 所指內(nèi)存區(qū)域不能重疊,函數(shù)返回指向 dest 的指針。   

注意:與 strcpy 相比, memcpy 并不是遇到 '\0' 就結(jié)束,而是一定會拷貝完 n 個字節(jié)。

 

memset

原型: extern void *memset(void *buffer, int c, int count);

用法: #include

功能:把 buffer 所指內(nèi)存區(qū)域的前 count 個字節(jié)設(shè)置成字符 c

說明:返回指向 buffer 的指針。

8 、 return  關(guān)鍵字

return  關(guān)鍵字終止一個函數(shù)并返回一個值。

#include "stdio.h"

 

add( int a, int b)

{

     return (a + b);

}

 

char * str( void )

{

     char * strc  = "This is c\n" ;

     return strc;

}

 

main( void )

{

    printf( "%d\n" ,add( 1 , 4 ));

    printf( "%s\n" ,str);

     return ;

}

看看上面這個函數(shù)的輸出,會有陷阱的

9 、柔性數(shù)組

講了很多關(guān)鍵字,現(xiàn)在討論一個酷的東西,以后也會經(jīng)常用到,柔性數(shù)組是可以自由變化長度的數(shù)組,對開發(fā)上來說是非常有用的。

C99 中,結(jié)構(gòu)體的最后一個元素允許是未知大小的數(shù)組,這就叫做柔性數(shù)組成員,但結(jié)構(gòu)體的柔性數(shù)組成員前面必須至少一個其他成員。

#include <stdio.h>

typedef struct _SoftArray{

     int len;

     int array[];

}SoftArray;

 

int main ()

{

     int len  = 10 ;

 

    printf( "The struct's size is %d\n" , sizeof (SoftArray));

}

C語言關(guān)鍵字(三)

我們可以看出, _SoftArray 結(jié)構(gòu)體的大小是 4 ,顯然,在 32 位操作系統(tǒng)下一個 int 型變量大小剛好為 4 ,也就說結(jié)構(gòu)體中的數(shù)組沒有占用內(nèi)存。為什么會沒有占用內(nèi)存,我們平時用數(shù)組時不時都要明確指明數(shù)組大小的嗎?但這里卻可以編譯通過呢?這就是我們常說的動態(tài)數(shù)組,也就是柔性數(shù)組。

#include <stdio.h>

#include <malloc.h>

typedef struct _SoftArray{

int len;

int array[];

}SoftArray;

int main ()

{

     int len = 10 ,i = ;

    

    SoftArray  * p = (SoftArray * )malloc( sizeof (SoftArray) +sizeof ( int ) * len);

    p -> len = len;

    

     for (i = ;i < p -> len;i ++ )

   {

        p -> array[i] = i + 1 ;

    }

     for (i = ;i < p -> len;i ++ )

   {  

        printf( "%d\n" ,p -> array[i]);

    }

 

    free(p);

 

     return ;

}

C語言關(guān)鍵字(三)

這代碼的作用是用柔性數(shù)組動態(tài)創(chuàng)建數(shù)組并輸出數(shù)組內(nèi)容,這里我就直接解釋解釋這兩句代碼

    SoftArray * = (SoftArray * )malloc( sizeof (SoftArray)  + sizeof ( int * 10 );

       p -> len  = 10 ;

第一句,主要是根據(jù)你要定義的數(shù)組長度和數(shù)據(jù)類型以及柔性數(shù)組本身的大小來開辟一塊內(nèi)存空間給柔性數(shù)組,第二個是定義 len 的長度,便于確定循環(huán)打印輸出


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI