test_cpp.c編程
#include <stdlib.h> #include <stdio.h> int main() { char c = 'c'; char *p = &c; char **pp = &p; const char **cpp = &p; char const **c_pp = &p; char * const *p_const_p = &p; char ** const ppc = &p; return 0; }
編譯的時候有以下warning:ubuntu
x@ubuntu:~/Desktop/const$ gcc text_cpp.c text_cpp.c: In function ‘main’: text_cpp.c:11:21: warning: initialization of ‘const char **’ from incompatible pointer type ‘char **’ [-Wincompatible-pointer-types] const char **cpp = &p; ^ text_cpp.c:12:22: warning: initialization of ‘const char **’ from incompatible pointer type ‘char **’ [-Wincompatible-pointer-types] char const **c_pp = &p; ^
看到上面的warning,第一時間就是有點懵,和"經驗不符「,咱們常見的是以下用法:ide
#include <stdlib.h> #include <stdio.h> int main() { char c = 'c'; const char *p = &c; char const *q = &c; char *const r = &c; return 0; }
上述用法都是ok的,編譯不會有warning。指針
查了不少資料,大體搞清楚了上面warning的緣由。上面warning緣由在《C專家編程》中有解釋,並且也參考了本文後面網址的資料。code
先來看看ANSI C中的規定:「兩個操做數都是指向有限定符或無限定符的相容類型的指針,左邊指針指向的類型必須具備右邊指針指向類型的所有限定符「。這句話的前半句強調類型,後半句強調限定符(修飾符)。 出現編譯warning的地方,若是不看修飾符const,賦值徹底沒有問題,問題出如今const修飾符。仍是上面那句話,須要進行兩點說明:
(1) 相容類型:在《ANSI C》的6.2.7節中,對相容類型(compatible type)的定義爲:Two types have compatible type if their types are the same.
(2) 指針指向類型:字面意思理解,應該指的是對指針僅進行一次解引用獲得的類型。對象
根據上面的說明,分別對下圖中的三種狀況進行解釋:it
char **pp = &p等式兩邊的兩個操做數都沒有限定符去,且pp指向的是char *類型,&p指向也是char *類型,是相容類型,符合前面那句話的前半句,兩個操做數都是指向無限定符的相容類型指針,那麼這個賦值ok,沒有任何問題。
io
char * const *pp = &p。pp 指向的是char * 類型,&p指向是char *類型,等式兩邊的類型相容,可是等式左邊pp指向的類型有const關鍵字修飾,右邊操做數沒有限定符。指向類型一個有限定符,一個沒有限定符,不符合前面那句話的前半句:兩個操做數都是指向有限定符或無限定符的相容類型的指針。編譯
須要注意的是左邊的const是pp指向類型*pp的限定符,指的是不能經過對pp一次解引用改變p的值,也就是說const是左邊操做數指向類型的限定符。function
接着看是否符合後半句,左邊指針指向的類型有const限定符,右邊指針指向的類型沒有限定符,符合後半句:左邊指針指向的類型必須具備右邊指針指向類型的所有限定符。 能夠這麼理解左邊指針指向的限定符集合是A={const, Ø}, 右邊指針指向類型的限定符集合是B={Ø},很顯然 A 具備B的全部限定符。
const char **pp = &p等式左邊pp指向的類型是const char *,&p指向是char *類型,不是相容類型。這是由於pp指向的類型是 *pp(const char *), *pp (const char *)沒有限定符,const 限定符修飾的不是*pp, 而是*pp指向的類型**p(char), 顯然這是對pp解引用二次了;&p指向的類型是p(char *)。 核心問題要肯定const限定符修飾的對象。