const是一個C語言的關鍵字,它限定一個變數不允許被改變,使用const在一定程式上可以提高程式的健壯性,另外,在觀看別人代碼的時候,清晰理解const所起的作用,對理解別人的程式有所幫助,
1、const簡介
下面簡單描述一下const,基本都是教科書的知識,const修飾的變數,其值存放在只讀資料段中,其值不能被改變,稱為只讀變數,關于什么是資料段,什么是代碼段,請看我之前的文章《C語言的記憶體分配》,
int const a; const int a;
上面兩條陳述句都可以將a宣告為一個整數,它的值不能被修改,這兩種方式你可以任意選一種即可,
常量在定義時可以被初始化,
int const a =15;
當指標和常量結合時,就會很有趣,因為有兩樣東西都可能成為常量,指標和它指向的物體,一般大家在大學考計算機二級和面試時經常會遇到的,
int *a;
a就是一個很普通的指向整型的指標,
int const *a;
這時則是一個指向整型常量的指標,也就是說,你可以修改指標的值,但是不能修改它指向的值,
int *const a;
這時a是一個指向整型的常量指標,這個指標是常量,它的值無法修改,但是你可以修改它所指向的整型的值,
int const *const a;
這個時候無論是指標本身還是它所指向的值都是常量,都不允許修改,
那么問題來了,就像C語言的運算子的優先級,這個東西很不好記憶,在實際開發中,我們直接多用()符號解決優先級的問題,上面指標和const結合那么麻煩,學習為了什么呢?
1、合理地使用關鍵字const可以使編譯器很自然地保護那些不希望被改變的引數,防止其被無意的代碼修改,簡而言之,這樣可以減少bug的出現,
2、正是基于上面的原因,一些優秀的開源代碼都會利用const這個屬性,深入理解后,方便我們閱讀理解一些優秀的開源代碼,
02、常量的應用
上文就簡述了一下教科書中的const定義,現在說一下const在我日常開發中的應用,
在單片機開發中
const定義一個常量,在單片機開發中,一個定義在函式體外的常量constint a = 5; 它是存盤在單片機內部Flash里的,不懂的同學請看之前的文章《C語言在STM32中的記憶體分配》,那么上文提到和指標結合時,也是存盤在內部Flash中嗎?我們來驗證一下
int data = https://www.cnblogs.com/Fireflycjd/p/0x1234; int const *a = &data; int *const b= &data; int const *const c= &data; int main(void) { int data1 = 0x1234; a =&data1; data1 = *b; data1 = *c; while(1); }
它們的記憶體分配如下

b和c是分配到內部flash的,a是分配到ram中的,其實這也很好理解,根據上面的const的定義,單片機在分配時,將不能修改的變數,也就是只讀變數放到flash中,可以讀寫的變數放到ram中,這個大家仔細想一下就明白了,
常量作為函式的引數
非指標引數(也就是傳值引數)不會被修改原始值,const對它是沒有意義的,所以這里只討論引數是指標加const的情況,
在上面看到,指標加const共3種情況,這里先討論int const *a; 也就是你可以修改指標的值,但是不能修改它指向的值,
int fun(int *p) { if(*p == 0xA5) { return*p; }else{ p++; return *p; } }
上面是個簡單的例子,也就是傳入一個指標,函式讀取指標指向的內容,執行不同的命令,類似串口接收,一個函式內部處理這些資料,但是不能修改,可能串口接收的資料在其他地方還有用,
在上述例子中,沒有問題的,因為代碼全在“掌控”中,函式內部是否進行寫操作,自己是知道的,但還有一個更規范的寫法,
int fun(int const *p) { if(*p == 0xA5) { return *p; }else{ p++; return *p; } }
這里寫法,就是明顯表現出自己的設計意圖,函式內部不可以對指標指向的內容進行修改,只能讀取,

如果嘗試修改,編譯器會直接報錯的,但是函式內部也是可以繞過去,修改的資料的,如下
int fun(const int *p) { int *p2 = p; /* 來個重名指標會繞過const的限制*/ *p2 += 1; return*p; }
那么對于int *const a;有沒有對應的使用場景呢?如下

這樣的介面設計,如果函式內部嘗試修改指標的值,也就是指標指向的位置,編譯器就會直接報錯,
不過這里例子很現實,因為即使去掉p2的const修飾,編譯器會直接報waring,因為p2是入參,這里只是簡單舉例子,大家理解意思就好,

在日常開發中,入參是intconst *a; 使用場景比較多,
C++中應用加const
C++中可以使用應用的語法,這里不再展開什么是應用,如下例子,C++函式引數中參考時也常加const修飾,如下
void find(constint &x) { ....... }
最后,舉兩個常用的標準C庫函式宣告,它們都是使用const的典范,
1.字串拷貝函式:char*strcpy(char*strDest,constchar *strSrc);
2.回傳字串長度函式:intstrlen(constchar *str);
3、#define和const
#define預編譯和const在某些情況下有些“混淆”,如下
#define MAX_NUM 5 int const max_num = 5; void fun(){ if(len >MAX_NUM) if(len> max_num) }
上述代碼5行和6行都能起效果,那么我們就詳細分析一下它們的區別
1、#define的資料是宏定義,它占用的是代碼段空間(單片機對應:內部flash),const定義一個資料型別,它占用的是data段(單片機對應:內部ram),
2、如上,#define是宏定義,在預編譯階段直接替換,而const是資料型別,
#define MAX_NUM 5 int const max_num = 5; int data[MAX_NUM]; intdata2[max_num];
上述代碼第4行是編譯不過的,因為max_num是一個int的資料型別變數,陣列定義的長度不能用變數,實際上,在更章節第一個例子,只用于判斷長度,#define更加合適,因為只要允許使用字面值常量的地方都可以使用宏定義,
3、define只是簡單的字串替換,沒有型別檢查,而const有對應的資料型別,是要進行判斷的,可以避免一些低級的錯誤,define只是簡單的字串替換會導致邊界效應,
比如定義
#define A 1 #define B A+3 #define C A/B3
那么c是多少呢?c=A/B3=A/A+33=1/1+33=10;所以這種用的時候可以直接都用個括號括起來,就不怕邊界效應了,
4、const不能重定義,不可以定義兩個一樣的,而define就比較牛氣了,它通過undef取消某個符號的定義,再重新定義,并還可以用于判斷宏定義是否存在,常用于頭檔案防止頭檔案被重復參考,
#ifndef GRAPHICS_H //防止graphics.h被重復參考 #defineGRAPHICS_H ……代碼…… #endif
5、const常量可以進行除錯的,define是不能進行除錯的,主要是預編譯階段就已經替換掉了,除錯的時候就沒它了,
點擊查看本文所在的專輯:C語言進階
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/423516.html
標籤:嵌入式
