Re: [問題] 為什麼兩個 pointer 不能轉 const

作者: OPIV (Monitor)   2015-02-09 15:57:08
※ 引述《purpose (purpose)》之銘言:
: 接前一篇的討論,我來解釋看看為什麼 const int 和 const int * 就可以?
: 首先強調一下,類似的事件,都會有一個被害人跟加害人。
: 而這樣的轉型:
: int **ptr;
: const int **thirdparty = ptr;
: 往往是被加害人利用來作案的第三者。
: 被害人:
: 受到 const 保護,可能被存放在唯讀區域的資料物件,
: 比如
: const Dog lucky; 或 const int maxNum;
: 加害人:
: Dog *p2lucky; 或 int *p2maxNum;
: 加害人往往透過 p2lucky->modify(xxx); 或 *p2maxNum = -1; 這樣的指令,
: 去破壞編譯器承諾的 const 保護。
: 但是正常情況下,編譯器不允許 p2maxNum = &maxNum; 這類轉型,
: 所以被害者與加害者,就好像白富美與魯肥宅一樣,
: 肥宅連走近白富美一公尺都做不到,因此犯罪事件無法發生。
: 但是,這個世界上是有掃廁所阿姨的,阿姨剛好就是能溝通白富美與魯肥宅的關鍵,
: 阿姨即為案件中的第三者 const int **thirdparty;
: 首先肥宅會喬裝成好人,騙阿姨把掃廁所的工作機會交給他:
: const int **thirdparty = &p2maxNum;
: 編譯器就好像阿姨的上司,如果是遵守 C++ 標準的編譯器,
: 會在這個時候就禁止阿姨讓「喬裝後的肥宅」(&p2maxNum) 混進來。
: 當肥宅混進去後,就會利用掃廁所的機會,接觸被害人:
: *thirdparty = &maxNum;
: 已知 thirdparty 等於 &p2maxNum,代入上式得到
: *(&p2maxNum) = &maxNum;
: 將 *& 相抵銷,就得到
: p2maxNum = &maxNum;
: 所以編譯器原本禁止的轉型,最終還是被無知的掃廁所阿姨破壞掉,讓肥宅得逞:
: *p2maxNum = -1;
: 然後不意外的話,會因為違法寫入記憶體,程式在執行時期會當掉。
: 回到最前面的問題,為什麼 const int ** 不行,而 const int * 就可以。
: 以上面的白富美為例,她的型態是 const int,要攻擊她就得是 int * 的指標。
: 今天 const int* 如果接受了攻擊者 int * 的位置:
: const int *掃廁所阿姨 = 魯肥宅; // int *魯肥宅
: 那就沒有空間可以去跟白富美接觸。
: 反之,如果
: const int *掃廁所阿姨 = &白富美: // const int 白富美;
: 那同樣也沒有空間去跟肥宅接觸。
: 因此 const int * 這樣的阿姨,是毫無殺傷力的阿姨,編譯器無須限制,無須理會。
對於(int *)可以轉(int const *)我還是有點不了解
例如以下程式
#include <stdio.h>
#include <stdlib.h>
void func(int const *b, int *fackb)
{
printf("value of *b: %d\n", *b);
*fackb += *b;
printf("value of *b: %d\n", *b);
}
int main(void)
{
int *a = (int *)malloc(sizeof(int));
*a = 5;
func(a, a);
free(a);
return 0;
}
root@localhost:~#./a.out
value of *b: 5
value of *b: 10
root@localhost:~#
像這樣的一隻程式,編譯器(gcc, g++, clang)都沒有任何抱怨
那這樣不就違反了*b是const的承諾了嗎?
作者: azureblaze (AzureBlaze)   2015-02-09 16:00:00
你寫入的是fackb沒錯啊const int*b 保證的是不能經由b修改
作者: purpose (秀才遇到肥宅兵)   2015-02-09 17:33:00
有的書用遙控器來形容指標或參考,const 加在 b 就只是承諾這隻遙控器的轉台功能被拿掉,轉台鍵按下去也不會通電發生作用。fackb 就是你跑去外面買另一隻遙控器來轉修正一下三樓推文,應該說 const 被加在 *b
作者: TobyH4cker (Toby (我要當好人))   2015-02-09 22:24:00
*b += *fackb; 應該就不能了
作者: adcvc (adcvc)   2015-02-09 23:12:00
int const *a和const int *a是一樣的
作者: purpose (秀才遇到肥宅兵)   2015-02-10 14:56:00
那就還是一樣,指標是遙控器,malloc出來的地方是電視機const 限制的始終還是遙控器本身,當 const 在 * 左邊也只是代表,遙控器被限制成不能把電視轉台,而不代表malloc製造出來的電視機,從此被你鎖住,變成不可更改這種規定很常見,比如 Windows 提供 CreateFile() 函數你可以呼叫他去到處亂開別人的檔案、設備,然後 OS 傳回的類指標,會看你帳號來給于權限,你的轉型就好像要把本來你只能唯讀的東西,開成有完全控制權限的指標一樣
作者: RealJack   2015-02-10 17:12:00
(int const*const*)=(int **)在g++沒問題,要不要貼個警告訊息參考一下
作者: purpose (秀才遇到肥宅兵)   2015-02-10 18:59:00
C 語言的隱式轉型規則,只有簡單加上一個 const 所以不會變成 const int *const * 但是 C++ 的隱式轉型規則可以直接把 int ** 隱式轉成 const int *const * 這很安全http://c-faq.com/ansi/constmismatch.html 倒數第二段所以 int ***p; int ** const*p2 = p; 對 gcc 是完全OK

Links booklink

Contact Us: admin [ a t ] ucptt.com