Re: [問題] 為什麼兩個 pointer 不能轉 const
※ 引述《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的承諾了嗎?
--
Sent from my Android
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 114.37.141.187
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1423468631.A.405.html
→
02/09 16:00, , 1F
02/09 16:00, 1F
→
02/09 16:01, , 2F
02/09 16:01, 2F
※ 編輯: OPIV (114.37.141.187), 02/09/2015 16:05:44
推
02/09 17:33, , 3F
02/09 17:33, 3F
→
02/09 17:34, , 4F
02/09 17:34, 4F
→
02/09 17:35, , 5F
02/09 17:35, 5F
推
02/09 17:50, , 6F
02/09 17:50, 6F
推
02/09 22:24, , 7F
02/09 22:24, 7F
→
02/09 23:12, , 8F
02/09 23:12, 8F
小弟還是有一點問題耶......
int main()
{
//*
//* 第一個例子
//*
//* (int const *) = (int *) => OK
//*
int *ip;
int const *icp2ip = ip; //* This is OK
//* 修改 const 的方法:
//* *ip = (int);
//*
//* 第二個例子:
//*
//* (int *) = (int const *) => WARNING
//*
int const *icp;
int *ip2icp = icp; //* This is NOT permitted
//* 修改 const 的方法:
//* *ip2icp = (int);
//*
//* 在第一個例子裡
//* *icp2ip 的值可以被 *ip 更改
//*
//* 在第二個例子裡
//* *icp 的值可以被 *ip2icp 更改
//*
//* 那麼為什麼第一個合法第二個就不行呢?
//*
return 0;
}
※ 編輯: OPIV (114.37.141.187), 02/10/2015 14:00:03
→
02/10 14:38, , 9F
02/10 14:38, 9F
→
02/10 14:41, , 10F
02/10 14:41, 10F
→
02/10 14:43, , 11F
02/10 14:43, 11F
→
02/10 14:44, , 12F
02/10 14:44, 12F
→
02/10 14:44, , 13F
02/10 14:44, 13F
→
02/10 14:45, , 14F
02/10 14:45, 14F
沒關係^^
只是,第一個不是還是可以用 *ip = xxx; 來更改 *icp2ip 嗎?
int *ip = (int *)malloc(sizeof(int));
const int *icp2ip = ip;
*ip = 5;
printf("%d", *icp2ip); // 5
*ip = 6;
printf("%d", *icp2ip); // 6
※ 編輯: OPIV (114.37.141.187), 02/10/2015 14:50:32
※ 編輯: OPIV (114.37.141.187), 02/10/2015 14:58:39
推
02/10 14:56, , 15F
02/10 14:56, 15F
→
02/10 14:57, , 16F
02/10 14:57, 16F
→
02/10 14:58, , 17F
02/10 14:58, 17F
→
02/10 14:59, , 18F
02/10 14:59, 18F
※ 編輯: OPIV (114.37.141.187), 02/10/2015 15:03:19
感謝 p大!
我好像懂了!
如果把"=" 看做是複製遙控器,那麼複製遙控器就有四種可能性:
1. (int *) = (int *)
2. (int *) = (const int *)
3. (const int *) = (int *)
4. (const int *) = (const int *)
要複製遙控器的時候,不可以用一般的遙控器去複製被鎖定的遙控器,即 (int *) = (
const int *),因為這樣"被鎖定"的特性就漏失了
而 (const int *) = (int *) 則可以理解成是複製了一般的遙控器之後再把它鎖定,這
樣應該是很合理的
所以 (int *) = (const *int) 是不合法的
而(const int *) = (int *) 則是合法的
※ 編輯: OPIV (114.37.141.187), 02/10/2015 15:21:49
※ 編輯: OPIV (114.37.141.187), 02/10/2015 15:25:37
推
02/10 15:26, , 19F
02/10 15:26, 19F
→
02/10 15:26, , 20F
02/10 15:26, 20F
→
02/10 15:27, , 21F
02/10 15:27, 21F
→
02/10 15:28, , 22F
02/10 15:28, 22F
糟糕!那我又有新問題了= =
如果照上面這樣講,這句應該是不會有 warning 的才對啊
(int const *const *) = (int **)
但是 clang 居然叫了!!!
※ 編輯: OPIV (114.37.141.187), 02/10/2015 15:57:26
推
02/10 17:12, , 23F
02/10 17:12, 23F
→
02/10 17:12, , 24F
02/10 17:12, 24F
R 大 here you are:
test3.c:6:20: warning: initializing 'const int *const *' with an expression of
type 'int **' discards qualifiers in nested pointer types
[-Wincompatible-pointer-types-discards-qualifiers]
int const *const *b = a;
^ ~
1 warning generated.
剛剛試過了,會 warning 的有
clang test.c
gcc test.c
不會 warning 的有
clang test.cpp
g++ test.cpp
g++ test.c
※ 編輯: OPIV (114.37.141.187), 02/10/2015 18:40:20
推
02/10 18:59, , 25F
02/10 18:59, 25F
→
02/10 19:00, , 26F
02/10 19:00, 26F
→
02/10 19:01, , 27F
02/10 19:01, 27F
所以說,我應該要強制轉型囉!?
這樣聽起來意思應該是說 C 的隱式轉型不會自動轉,所以丟 warning 告知你一下,C++
會,所以沒差,是這樣嗎?
那前面的(const int *) = (int *)那些為什麼不需要強制轉型呢?
有沒有什麼資料是關於轉型的規則的呢?
※ 編輯: OPIV (114.37.141.187), 02/10/2015 22:38:50
推
02/10 23:31, , 28F
02/10 23:31, 28F
→
02/10 23:32, , 29F
02/10 23:32, 29F
嗯嗯 感謝 p 大的幫助
我找到一個把 const 說明得很好的文件
應該對很多人會有幫助
"http://www.dansaks.com/articles/1998-08 What const Really Means.pdf"
※ 編輯: OPIV (114.37.141.187), 02/11/2015 12:04:22
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 4 之 4 篇):