2015年7月13日 星期一

有著 const 修飾的 c pointer

經過 os kernel 修煉之後, 我本來以為對指標已達「略懂」的境界, 不過看了《[問題] 為什麼兩個 pointer 不能轉 const》 (該篇的討論有答案) 之後, 我才知道還有不足, 這次不是記憶體佈局的問題, 是在 compiler 這個階段。

有的人說指標很簡單, 我不知道他是真的把指標搞懂了還是誤會了指標的困難度, 指標的複雜度有兩方面: run time 和 compiler time。而這個 const 是在 compiler time, 怎麼把這個 const 指標寫對是很困難的, 而 c 和 c++ 又有不同的觀點。

const int *  *  * p1;
      int *  *  * p2;
p1=p2;   

上述的程式碼無法正常 compile, 我很驚訝,

const int * p1;
      int *p2;
p1=p2;   

這樣就可以, 為什麼多了幾顆星星就不行, 許多人已經提出答案了, 就不重複說明了, 參考以下連結。

ref:
  1. const 的使用 (4) - 基礎測驗解答篇
  2. Re: [問題] 為什麼兩個 pointer 不能轉 const
a.cpp, b.cpp 分別用來觀察在 dereference 時, 取到的型別是什麼?

a.cpp
 1 #include <stdio.h>
 2 #include <typeinfo>
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 void func(const char *const * tokens, int len)
 8 {
 9   for (int i=0 ; i < len ; ++i)
10     cout << *(tokens+i) << endl;
11 }
12 
13 int main(int argc, char *argv[])
14 {
15   char s1[]="abc";
16   char s2[]="xyz";
17   char *tokens[3] = {s1, s2};
18   func(tokens, 2);
19 
20   int *  *  const* p1;
21 
22   cout << "p1 type: " << typeid(p1).name() << endl;
23   cout << "*p1 type: " << typeid(*p1).name() << endl;
24   cout << "**p1 type: " << typeid(**p1).name() << endl;
25   cout << "***p1 type: " << typeid(***p1).name() << endl;
26   return 0;
27 }



result1
p1 type: PKPPi
*p1 type: PPi
**p1 type: Pi
***p1 type: i

PK 是一個 const pointer, P 則是 non-const pointer。

b.cpp
 1 #include <stdio.h>
 2 #include <typeinfo>
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 void func(const char *const * tokens, int len)
 8 {
 9   for (int i=0 ; i < len ; ++i)
10     cout << *(tokens+i) << endl;
11 }
12 
13 int main(int argc, char *argv[])
14 {
15   char s1[]="abc";
16   char s2[]="xyz";
17   char *tokens[3] = {s1, s2};
18   func(tokens, 2);
19 
20   int const*  *  * p1;
21 
22   cout << "p1 type: " << typeid(p1).name() << endl;
23   cout << "*p1 type: " << typeid(*p1).name() << endl;
24   cout << "**p1 type: " << typeid(**p1).name() << endl;
25   cout << "***p1 type: " << typeid(***p1).name() << endl;
26   return 0;
27 }


result2
p1 type: PPPKi
*p1 type: PPKi
**p1 type: PKi
***p1 type: i


手工打造的示意圖
寄件者 ??

再來便是如何正確傳入 const pointer 的問題, 你很想這麼做, 但編譯器老是發出錯誤或是警告訊息嗎? 所以你乾脆不使用 const 了, 我也曾經遇到類似的麻煩事, c.cpp 把幾種情況列出來, c.cpp 無法通過編譯, 只是列出語法, 使用了正確的宣告後, 編譯器終於安靜下來了, 用 c++ compiler 才會安靜, 用 c compiler 一樣會發出警告。請參考 ref 2 的討論。

c.cpp
 1 #include <stdio.h>
 2 #include <typeinfo>
 3 #include <iostream>
 4 
 5 using namespace std;
43   char s1[]="abc";
44   char s2[]="xyz";
45   char s3[]="lmk";
 6 
11 
12 //const char * const tokens[]={s1, s2};
13 void func(const char * const* tokens, int len)
14 {
15   for (int i=0 ; i < len ; ++i)
16     cout << *(tokens+i) << endl;
17 }
18 
19 //const char * tokens[]={s1, s2};
20 void func(const char * * tokens, int len)
21 {
22   for (int i=0 ; i < len ; ++i)
23     cout << *(tokens+i) << endl;
24 }
25 
26 //char * tokens[]={s1, s2};
27 void func(const char * const* tokens, int len)
28 {
29   for (int i=0 ; i < len ; ++i)
30     cout << *(tokens+i) << endl;
31 }
32 
33 //char * tokens[]={s1, s2};
34 void func(char * * tokens, int len)
35 {
36   for (int i=0 ; i < len ; ++i)
37     cout << *(tokens+i) << endl;
38 }

ref:

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。