[描述] 在 C、C++、D 和 JavaScript 編程語言中,const是一個類型限定符一個應用於數據類型的關鍵字,表示數據是隻讀的。Const - Wiki編程
一個正常的類型定義:編程語言
int num;
複製代碼
首先,編譯器在讀取 int num;
的時候,從左往右讀取:spa
int
代表是整型數據,分配 xxx 個字節 ( xxx 根據不一樣平臺數量不一樣 ),num
代表是一個名爲 num
的數據 ,;
表示結束 ( 固然有些語言是沒有 ;
可是有換行,即讀取到換行符,表示結束 ),int num;
最後表示是一個名爲 num
且可讀寫的整型數據。畫內存區塊:(這很簡單,不用解釋了~)指針
// 讀 (read)
int var = num; // OK
// 寫 (write)
num = 100; // OK
/****** RW *****/ /***** RW *****/
/**/ var /**/ <-- read - /**/ num /**/ <-- write - 100
/**************/ /**************/
複製代碼
那麼加上 const
會變成怎樣呢?code
// [] 表示可選
[const] int [const] num;
// 即 有:
const int num; // 第一種
// 或
int const num; // 第二種
// 或 , 這裏會報 Duplicate 'const' declaration specifier.
// 即至左向右的第二個 const 不能加。
const int const num; // 第?種
// 因此共 兩種 寫法。
複製代碼
[ 第一種 ] 首先,編譯器在讀取 const int num;
的時候,從左往右讀取:ip
const
代表是隻讀的數據類型,int
代表是整型數據,分配 xxx 個字節 ( xxx 根據不一樣平臺數量不一樣 ),const int
就代表是一個只讀的整型數據;num
代表是一個名爲 num
的數據 ,;
表示結束 ( 固然有些語言是沒有 ;
可是有換行,即讀取到換行符,表示結束 )const int num;
最後表示是一個名爲 num
的只讀整型數據。畫內存區塊:內存
// 讀 (read)
int var = num; // OK
// 寫 (write) 🚫
num = 100; // error
/****** RW *****/ /***** RO *****/
/**/ var /**/ <-- read - /**/ num /**/ <-X- write 🚫 - 100
/**************/ /**************/
複製代碼
[ 第二種 ] 首先,編譯器在讀取 int const num;
的時候,從左往右讀取:ci
int
代表是整型數據,分配 xxx 個字節 ( xxx 根據不一樣平臺數量不一樣 ),const
代表是隻讀的數據類型,int const
就代表是一個只讀的整型數據;num
代表是一個名爲 num
的數據 ,;
表示結束 ( 固然有些語言是沒有 ;
可是有換行,即讀取到換行符,表示結束 )const int num;
最後表示是一個名爲 num
的只讀整型數據。畫內存區塊:get
// 讀 (read)
int var = num; // OK
// 寫 (write) 🚫
num = 100; // error
/****** RW *****/ /***** RO *****/
/**/ var /**/ <-- read - /**/ num /**/ <-X- write 🚫 - 100
/**************/ /**************/
複製代碼
明顯地,第一種和第二種結果是同樣的,由於編譯器在讀取的時候,最後產生的語義是同樣的,那麼結果固然是同樣的。編譯器
結:int num;
和 [const] int [const] num;
惟一區別是 num
自身這塊內存是否可寫,即後者的內存寫功能被關閉了。
int * num;
複製代碼
首先,編譯器在讀取 int * num;
的時候,從左往右讀取:
int
代表是整型數據,分配 xxx 個字節 ( xxx 根據不一樣平臺數量不一樣 ),*
,因爲是在數據定義中存在,即代表是指針類型,int *
, 代表是一個整型的指針類型數據 ,num
代表是一個名爲 num
的數據 ,;
表示結束 ( 固然有些語言是沒有 ;
可是有換行,即讀取到換行符,表示結束 ),int * num;
最後表示是一個名爲 num
且保存着可讀寫的整型的指針數據 ( 保存整型數據內存地址的數據 )。畫內存區塊:
int no;
int * num = &no;
// *num 讀 (read)
int var = *num; // OK, var = no
// *num 寫 (write)
*num = 200; // OK
// num 讀
int * n1 = num; // OK
// num 寫
num = &no; // OK
/****** RW *****/ /************* RW ***********/
/**/ var /**/ <-- read - /**/ no /**/ <-- write - 100
/**************/ /***** RW(對於 num 而言) *****/
⬇️ ⬆️
⬇️(read) ⬆️(write, 200) (*num)
⬇️ ⬆️
/****** RW *****/ /************* RW *************/
/**/ n1 /**/ <-- read - /**/ num /**/ <-- write - &no
/**************/ /******************************/
複製代碼
對於 num
指針類型,這裏就出現了兩個內存區塊:
num
自身的內存區塊 ( num 保存了 no
變量的內存區塊地址 )no
自身的內存區塊地址一樣的方法加個 const
看看?
從形式上看無非是增長了一個修飾位。
// [] 表示可選
[const] int [const] * [const] num;
// 即 有:
const int * num; // 第一種
// 或
int const * num; // 第二種
// 或
int * const num; // 第三種
// 或
const int * const num; // 第四種, 等價於 int const * const num;
// 或 , 這裏會報 Duplicate 'const' declaration specifier.
// 即至左向右的第二個 const 不能加。
const int const * const num; // 第?種
// 因此一共四種寫法。
複製代碼
[第一種] 首先,編譯器在讀取 const int * num;
的時候,從左往右讀取:
const
代表是隻讀的數據類型,int
代表是整型數據,分配 xxx 個字節 ( xxx 根據不一樣平臺數量不一樣 ),const int
就代表是一個只讀的整型數據;*
,因爲是在數據定義中存在,即代表是指針類型數據,int *
, 代表是一個只讀的整型的指針類型,num
代表是一個名爲 num
的數據 ,;
表示結束 ( 固然有些語言是沒有 ;
可是有換行,即讀取到換行符,表示結束 ),const int * num;
最後表示是一個名爲 num
且保存只讀的整型的指針數據。畫內存區塊:
int no;
const int * num = &no;
// *num 讀 (read)
// 右值 *num 可理解成,從 num 中獲得 no 的內存地址,再從 no 中讀取內容。
int var = *num; // OK
// *num 寫 (write) 🚫
// 左值 *num 可理解成,從 num 中獲得 no 的內存地址,因爲代表了 no 的地址是隻讀指向,因此沒法從 no 中讀取內容。
*num = 200; // error
// num 讀
int * n1 = num; // OK
// num 寫
num = no; // OK
/****** RW *****/ /************* RW ***********/
/**/ var /**/ <-- read - /**/ no /**/ <-- write - 100
/**************/ /***** RO(對於 num 而言) *****/
⬇️ ⬆️
⬇️(read) ⬆️(write, 200 🚫) (*num)
⬇️ ⬆️
/****** RW *****/ /************* RW *************/
/**/ n1 /**/ <-- read - /**/ num /**/ <-- write - &no
/**************/ /******************************/
複製代碼
圖可能很差理解 ,這裏代表的是 num
自身的內存可讀寫,可是 num
保存的內存地址是隻讀的。( num 自身的內存地址由系統(程序)保存着 )
即,系統保存着 num
內存地址且可讀寫,num
保存着 no
的內存地址,但修飾成了只讀。
[第二種] 首先,編譯器在讀取 int const * num;
的時候,從左往右讀取:
int
代表是整型數據,分配 xxx 個字節 ( xxx 根據不一樣平臺數量不一樣 ),const
代表是隻讀的數據類型,int const
就代表是一個只讀的整型數據;*
,因爲是在數據定義中存在,即代表是指針類型,int const *
, 代表是一個只讀的整型的指針類型數據,num
代表是一個名爲 num
的數據 ,;
表示結束 ( 固然有些語言是沒有 ;
可是有換行,即讀取到換行符,表示結束 ),int const * num;
最後表示是一個名爲 num
且保存只讀的整型的指針數據。第一種和第二種,語義上是同樣的因此結果確定是同樣的。
[第三種] 首先,編譯器在讀取 int * const num;
的時候,從左往右讀取:
int
代表是整型數據,分配 xxx 個字節 ( xxx 根據不一樣平臺數量不一樣 ),*
,因爲是在數據定義中存在,即代表是指針類型,int *
就代表是一個整型的指針類型數據;const
代表是隻讀的數據類型,int * const
, 代表是一個整型的指針類型的只讀的數據,num
代表是一個名爲 num
的數據 ,;
表示結束 ( 固然有些語言是沒有 ;
可是有換行,即讀取到換行符,表示結束 ),int * const num;
最後表示是一個名爲 num
且整型的指針類型的只讀的數據。畫內存區塊:
int no;
int * const num = &no;
// *num 讀 (read)
// 右值 *num 可理解成,從 num 中獲得 no 的內存地址,再從 no 中讀取內容。
int var = *num; // OK
// *num 寫 (write)
// 左值 *num 可理解成,從 num 中獲得 no 的內存地址,再向 no 中寫入內容。
*num = 200; // OK
// num 讀
int * n1 = num; // OK
// num 寫 🚫
num = no; // error
/****** RW *****/ /************* RW ***********/
/**/ var /**/ <-- read - /**/ no /**/ <-- write - 100
/**************/ /***** RW(對於 num 而言) *****/
⬇️ ⬆️
⬇️(read) ⬆️(write, 200) (*num)
⬇️ ⬆️
/****** RW *****/ /************* RO *************/
/**/ n1 /**/ <-- read - /**/ num /**/ <-X- write 🚫 - &no
/**************/ /******************************/
複製代碼
[第四種] 首先,編譯器在讀取 const int * const num;
的時候,從左往右讀取:
const
代表是隻讀的數據類型,int
代表是整型數據,分配 xxx 個字節 ( xxx 根據不一樣平臺數量不一樣 )const int
就代表是一個只讀的整型數據,*
,因爲是在數據定義中存在,即代表是指針類型,int const *
, 代表是一個只讀的整型的指針類型的數據,const
代表是隻讀的數據類型,int const * const
代表是一個只讀的整型的指針類型的只讀的數據num
代表是一個名爲 num
的數據 ,;
表示結束 ( 固然有些語言是沒有 ;
可是有換行,即讀取到換行符,表示結束 ),int * const num;
最後表示是一個名爲 num
且只讀的整型的指針類型的只讀的數據。畫內存區塊:
int no;
int * const num = &no;
// *num 讀 (read)
// 右值 *num 可理解成,從 num 中獲得 no 的內存地址,再從 no 中讀取內容。
int var = *num; // OK
// *num 寫 (write) 🚫
// 左值 *num 可理解成,從 num 中獲得 no 的內存地址,因爲代表了 no 的地址是隻讀指向,因此沒法從 no 中讀取內容。
*num = 200; // error
// num 讀
int * n1 = num; // OK
// num 寫 🚫
num = no; // error
/****** RW *****/ /************* RW ***********/
/**/ var /**/ <-- read - /**/ no /**/ <-- write - 100
/**************/ /***** RO(對於 num 而言) *****/
⬇️ ⬆️
⬇️(read) ⬆️(write, 200 🚫 ) (*num)
⬇️ ⬆️
/****** RW *****/ /************* RO *************/
/**/ n1 /**/ <-- read - /**/ num /**/ <-X- write 🚫 - &no
/**************/ /******************************/
複製代碼
/// 基本類型
// num 的內存可讀寫
int num;
// num 的內存只讀,不可寫
const int num; // 等價於 int const num;
/// 一級指針類型
// num 自身內存可讀寫; num 指向的內存可讀寫
int * num;
// num 自身內存可讀寫; num 指向的內存只讀,不可寫
const int * num; // 等價於 int const * num;
// num 自身內存只讀,不可寫; num 指向的內存可讀寫
int * const num;
// num 自身內存只讀,不可寫; num 指向的內存只讀,不可寫
const int * const num;
複製代碼
const
修飾無論放那都是隻讀。( 由於從語義上看無論 const
放那它也只有一種結果 )const
一旦緊挨着變量名,即自身的內存只讀,其它狀況都是指向的內存只讀。*
,那麼要考慮的就是 ( x + 1 ) 個內存塊的問題了。int const
和 const int
,編譯器都會直接轉換成 const int
。二級指針類型的例子:
int N = 8;
int const NC = 8;
int * n;
int * const n0 = NULL;
int const * n1 = NULL;
int const * const n2 = NULL;
int const ** const n3 = NULL;
int * const * const n4 = NULL;
// [] 表示可選
// [const] int [const] * [const] * [const] num;
// num 自身的內存,*num 指向的內存, **num 指向的內存,一共三塊內存
// num 的數據類型是:int ** const, *num 的數據類型是:int * [const], **num 的數據類型是:int .
// const 修飾 num 自身內存,即 num 自身的內存只讀
int ** const num = NULL;
**num = N; // OK
*num = n; // OK
*num = n0; // OK
num = &n0; // error 🚫
// num 自身的內存,*num 指向的內存, **num 指向的內存,一共三塊內存
// num 的數據類型是:int * [const] * , *num 的數據類型是:int * const, **num 的數據類型是:int .
// const 修飾 *num 指向的內存,即 *num 指向的內存只讀
int * const * num;
**num = N; // OK
*num = n0; // error 🚫
num = &n0; // OK
num = &n; // OK
// num 自身的內存,*num 指向的內存, **num 指向的內存,一共三塊內存
// num 的數據類型是:int const **, *num 的數據類型是:int [const] * [const], **num 的數據類型是:int const .
// const 修飾 **num 指向的內存,即 **num 指向的內存只讀
int const ** num;
**num = NC; // error 🚫
*num = n; // OK
*num = n0; // OK
*num = n1; // OK
*num = n2; // OK
num = n3; // OK
// num 自身的內存,*num 指向的內存, **num 指向的內存,一共三塊內存
// num 的數據類型是:int * const * const, *num 的數據類型是:int * const, **num 的數據類型是:int .
// 最右邊的 const 修飾 num 自身內存,即 num 自身的內存只讀
// const 修飾 *num 指向的內存,即 *num 指向的內存只讀
int * const * const num = NULL;
**num = N; // OK
*num = n0; // error 🚫
num = n4; // error 🚫
複製代碼
若是對上面的內容有疑惑,那麼就動手畫畫內存圖~~吧 !!!