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