最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

const關(guān)鍵字到底該什么用?

2019-03-15 16:06 作者:韋東山  | 我要投稿


文 | 守望先生

經(jīng)授權(quán)轉(zhuǎn)載自公眾號(hào)編程珠璣(id:shouwangxiansheng)


前言

我們都知道使用const關(guān)鍵字限定一個(gè)變量為只讀,但它是真正意義上的只讀嗎?實(shí)際中又該如何使用const關(guān)鍵字?在解答這些問(wèn)題之前,我們需要先理解const關(guān)鍵字的基本使用。本文說(shuō)明C中的const關(guān)鍵字,不包括C++。


基本介紹

const是constant的簡(jiǎn)寫,是不變的意思。但并不是說(shuō)它修飾常量,而是說(shuō)它限定一個(gè)變量為只讀。


修飾普通變量

例如:


const int NUM = 10; //與int const NUM等價(jià)

NUM = 9;? //編譯錯(cuò)誤,不可再次修改


由于使用了const修飾NUM,使得NUM為只讀,因此嘗試對(duì)NUM再次賦值的操作是非法的,編譯器將會(huì)報(bào)錯(cuò)。正因如此,如果需要使用const修飾一個(gè)變量,那么它只能在開始聲明時(shí)就賦值,否則后面就沒有機(jī)會(huì)了(后面會(huì)講到一種特殊情況)。


修飾數(shù)組

例如使用const關(guān)鍵字修飾數(shù)組,使其元素不允許被改變:


const int arr[] = {0,0,2,3,4}; //與int const arr[]等價(jià)

arr[2] = 1; //編譯錯(cuò)誤


試圖修改arr的內(nèi)容的操作是非法的,編譯器將會(huì)報(bào)錯(cuò):


error: assignment of read-only location ‘a(chǎn)rr[2]’


修飾指針

修飾指針的情況比較多,主要有以下幾種情況:

1.const 修飾 *p,指向的對(duì)象只讀,指針的指向可變:


int a = 9;

int b = 10;

const int *p = &a;//p是一個(gè)指向int類型的const值,與int const *p等價(jià)

*p = 11;? ? //編譯錯(cuò)誤,指向的對(duì)象是只讀的,不可通過(guò)p進(jìn)行改變

p = &b;? ? ?//合法,改變了p的指向


這里為了便于理解,可認(rèn)為const修飾的是*p,通常使用*對(duì)指針進(jìn)行解引用來(lái)訪問(wèn)對(duì)象,因而,該對(duì)象是只讀的。


2.const修飾p,指向的對(duì)象可變,指針的指向不可變:


int a = 9;

int b = 10;

int * const p = &a;//p是一個(gè)const指針

*p = 11;? ? //合法,

p = &b;? ? ?//編譯錯(cuò)誤,p是一個(gè)const指針,只讀,不可變


3.指針不可改變指向,指向的內(nèi)容也不可變


int a = 9;

int b = 10;

const int * const p = &a;//p既是一個(gè)const指針,同時(shí)也指向了int類型的const值

*p = 11;? ? //編譯錯(cuò)誤,指向的對(duì)象是只讀的,不可通過(guò)p進(jìn)行改變

p = &b;? ? ?//編譯錯(cuò)誤,p是一個(gè)const指針,只讀,不可變


看完上面幾種情況之后是否會(huì)覺得混亂,并且難以記憶呢?我們使用一句話總結(jié):

const放在*的左側(cè)任意位置,限定了該指針指向的對(duì)象是只讀的;const放在*的右側(cè),限定了指針本身是只讀的,即不可變的。


如果還不是很好理解,我們可以這樣來(lái)看,去掉類型說(shuō)明符,查看const修飾的內(nèi)容,上面三種情況去掉類型說(shuō)明符int之后,如下:


const *p; //修飾*p,指針指向的對(duì)象不可變

* const p; //修飾p,指針不可變

const * const p; //第一個(gè)修飾了*p,第二個(gè)修飾了p,兩者都不可變


const右邊修飾誰(shuí),就說(shuō)明誰(shuí)是不可變的。上面的說(shuō)法僅僅是幫助理解和記憶。借助上面這種理解,就會(huì)發(fā)現(xiàn)以下幾種等價(jià)情況:


const int NUM = 10; //與int const NUM等價(jià)

int a = 9;

const int *p? = &a;//與int const *p等價(jià)

const int arr[] = {0,0,2,3,4}; //與int const arr[]等價(jià)


const關(guān)鍵字該怎么用

前面介紹了這么多內(nèi)容,是不是都常用呢?const關(guān)鍵字到底該怎么用?


修飾函數(shù)形參

實(shí)際上,為我們可以經(jīng)常發(fā)現(xiàn)const關(guān)鍵字的身影,例如很多庫(kù)函數(shù)的聲明:


char *strncpy(char *dest,const char *src,size_t n);//字符串拷貝函數(shù)

int? *strncmp(const char *s1,const char *s2,size_t n);//字符串比較函數(shù)


通過(guò)看strncpy函數(shù)的原型可以知道,源字符串src是只讀的,不可變的,而dest并沒有該限制。我們通過(guò)一個(gè)小例子繼續(xù)觀察:


//test.c

#include<stdio.h>

void myPrint(const char *str);

void myPrint(const char *str)

{

? ? str[0] = 'H';

? ? printf("my print:%s\n",str);

}

int main(void)

{

? ? char str[] = "hello world";

? ? myPrint(str);

? ? return 0;

}


在這個(gè)例子中,我們不希望myPrint函數(shù)修改傳入的字符串內(nèi)容,因此入?yún)⑹褂昧薱onst限定符,表明傳入的字符串是只讀的,因此,如果myPrint函數(shù)內(nèi)部如果嘗試對(duì)str進(jìn)行修改,將會(huì)報(bào)錯(cuò):


$ gcc -o test test.c

test.c:6:12: error: assignment of read-only location ‘*str’

? ? ?str[0] = 'H';


因此,我們自己在編碼過(guò)程中,如果確定傳入的指針參數(shù)僅用于訪問(wèn)數(shù)據(jù),那么應(yīng)該將其聲明為一個(gè)指向const限定類型的指針,避免函數(shù)內(nèi)部對(duì)數(shù)據(jù)進(jìn)行意外地修改。


修飾全局變量

我們知道,使用全局變量是一種不安全的做法,因?yàn)槌绦虻娜魏尾糠侄寄軌驅(qū)θ謹(jǐn)?shù)據(jù)進(jìn)行修改。而如果對(duì)全局變量增加const限定符(假設(shè)該全局?jǐn)?shù)據(jù)不希望被修改),就可以避免被程序其他部分修改。這里有兩種使用方式。

第一種,在a文件中定義,其他文件中使用外部聲明,例如:

a.h


//a.h

const int ARR[] = {0,1,2,3,4,5,6,7,8,9};? //定義int數(shù)組


b.c


//b.c

extern const int ARR[];? ?//注意,這里不能再對(duì)ARR進(jìn)行賦值

//后面可以使用ARR


第二種,在a文件中定義,并使用static修飾,b文件包含a文件,例如:

a.h


//a.h

static const int ARR[] = {0,1,2,3,4,5,6,7,8,9};? //定義int數(shù)組


b.c


//b.c

#include<a.h>

//后面可以使用ARR


注意,這里必須使用static修飾,否則多個(gè)文件包含導(dǎo)致編譯會(huì)出現(xiàn)重復(fù)定義的錯(cuò)誤。有興趣的可以嘗試一下。


const修飾的變量是真正的只讀嗎?

使用const修飾之后的變量真的是完全的只讀嗎?看下面這個(gè)例子:


#include <stdio.h>

int main(void)

{

? ? const int a = 2018;

? ? int *p = &a;

? ? *p = 2019;

? ? printf("%d\n",a);

? ? return 0;

}


運(yùn)行結(jié)果:


2019


可以看到,我們通過(guò)另外定義一個(gè)指針變量,將被const修飾的a的值改變了。那么我們不禁要問(wèn),const到底做了什么呢?它修飾的變量是真正意義上的只讀嗎?為什么它修飾的變量的值仍然可以改變?


#include<stdio.h>

int main(void)

{

? ? int a = 2019;

? ? //const int a = 2019;

? ? printf("%d\n",a);

? ? return 0;

}


我們分別獲取有const修飾和無(wú)const修飾的匯編代碼。

無(wú)const修飾,匯編代碼:


.LC0:

? ? ? ? .string "%d\n"

main:

? ? ? ? push? ? rbp

? ? ? ? mov? ? ?rbp, rsp

? ? ? ? sub? ? ?rsp, 16

? ? ? ? mov? ? ?DWORD PTR [rbp-4], 2019

? ? ? ? mov? ? ?eax, DWORD PTR [rbp-4]

? ? ? ? mov? ? ?esi, eax

? ? ? ? mov? ? ?edi, OFFSET FLAT:.LC0

? ? ? ? mov? ? ?eax, 0

? ? ? ? call? ? printf

? ? ? ? mov? ? ?eax, 0

? ? ? ? leave

? ? ? ? ret


有const修飾,匯編代碼:


.LC0:

? ? ? ? .string "%d\n"

main:

? ? ? ? push? ? rbp

? ? ? ? mov? ? ?rbp, rsp

? ? ? ? sub? ? ?rsp, 16

? ? ? ? mov? ? ?DWORD PTR [rbp-4], 2019

? ? ? ? mov? ? ?eax, DWORD PTR [rbp-4]

? ? ? ? mov? ? ?esi, eax

? ? ? ? mov? ? ?edi, OFFSET FLAT:.LC0

? ? ? ? mov? ? ?eax, 0

? ? ? ? call? ? printf

? ? ? ? mov? ? ?eax, 0

? ? ? ? leave

? ? ? ? ret


我們發(fā)現(xiàn),并沒有任何差異!當(dāng)然這一個(gè)例子并不能說(shuō)明所有的問(wèn)題。但是我們要知道的是,const關(guān)鍵字告訴了編譯器,它修飾的變量不能被改變,如果代碼中發(fā)現(xiàn)有類似改變?cè)撟兞康牟僮?,那么編譯器就會(huì)捕捉這個(gè)錯(cuò)誤。


那么它在實(shí)際中的意義之一是什么呢?幫助程序員提前發(fā)現(xiàn)問(wèn)題,避免不該修改的值被意外地修改,但是無(wú)法完全保證不被修改!例如我們可以通過(guò)對(duì)指針進(jìn)行強(qiáng)轉(zhuǎn):


#include<stdio.h>

void myPrint(const char *str);

void myPrint(const char *str)

{

? ? char *b = (char *)str;

? ? b[0] = 'H';

? ? printf("my print:%s\n",b);


}

int main(void)

{

? ? char str[] = "hello world";

? ? myPrint(str);

? ? return 0;

}


運(yùn)行結(jié)果:


my print:Hello world


也就是說(shuō),const關(guān)鍵字是給編譯器用的,幫助程序員提早發(fā)現(xiàn)可能存在的問(wèn)題。


總結(jié)

介紹了這么多,關(guān)鍵點(diǎn)如下:

const關(guān)鍵字讓編譯器幫助我們發(fā)現(xiàn)變量不該被修改卻被意外修改的錯(cuò)誤。

const關(guān)鍵字修飾的變量并非真正意義完完全全的只讀。

對(duì)于不該被修改的入?yún)?,?yīng)該用const修飾,這是const使用的常見姿勢(shì)。

const修飾的變量只能正常賦值一次。

不要試圖將非const數(shù)據(jù)的地址賦給普通指針。

不要忽略編譯器的警告,除非你很清楚在做什么。

雖然可以通過(guò)某種不正規(guī)途徑修改const修飾的變量,但是永遠(yuǎn)不要這么做。


---END---

關(guān)注公眾號(hào)baiwenkeji第一時(shí)間獲得嵌入式干貨。
技術(shù)交流加個(gè)人威信13266630429,驗(yàn)證:B站

const關(guān)鍵字到底該什么用?的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
贞丰县| 七台河市| 琼结县| 梅州市| 清苑县| 自治县| 宣武区| 瑞金市| 钦州市| 镇安县| 赞皇县| 宝应县| 寻乌县| 武隆县| 宝坻区| 稷山县| 浙江省| 泰和县| 阿巴嘎旗| 吉林省| 连城县| 临邑县| 桑植县| 清远市| 县级市| 嘉峪关市| 行唐县| 土默特左旗| 渭南市| 札达县| 金川县| 龙门县| 平武县| 东乡县| 乌兰察布市| 霍邱县| 固镇县| 麦盖提县| 通江县| 含山县| 伊金霍洛旗|