万物皆“指针”

万物皆“指针”

前言

众所周知,C/C++的知识的精髓是指针,指针的本质是内存地址,可无论是普通变量,还是类的成员变量,谁还能没有一个内存地址呢,既然普通变量有内存地址,那我们也能像对指针变量那样对普通变量进行操作,也就是指针的 * 操作和 -> 操作。

测试

打开compiler explorer,其网址如下:https://gcc.godbolt.org/

定义一个普通的变量a,写一个func_1函数,借用指针变量p,通过 * 操作,来给变量a赋值,再写一个函数func_2,不借助指针变量,直接对变量a的地址进行 * 操作来给变量赋值

int a = 0;

void func_1()
{
   int* p = &a;
   *p = 1;
}

void func_2()
{
    *(int*)&a =1;
}

对比一下汇编,func_1函数 用了三条指令,func_2就简洁多了,直接对变量a的内存地址写:1,仅一条指令就完成了赋值,如你所见,普通变量也能做指针 * 操作,只要知道变量a的地址,就可以进行指针的 * 操作,还省掉了指针的开销,更简单直接。
在这里插入图片描述
当然还可以把func_2写的更极端一些,假设a的内存地址是:ox1234我们就可以把func_2函数改写成这样子
在这里插入图片描述
我们再写一个函数func_3,用最常规的方式给变量a赋值

int a = 0; //a address = 0x1234

void func_1()
{
   int* p = &a;
   *p = 1;
}

void func_2()
{
    *(int*)&a =1;
}

void func_3()
{
    a =1;
}

在这里插入图片描述可以发现func_2函数和func_3函数汇编指令完全相同
在这里插入图片描述
所以如你所见,你最熟悉的变量读写都等同于对变量地址的指针 * 操作,正如变量的定义所言,变量不过是内存地址的别名,同样的道理,不借助指针变量,我们也可以通过指针的 -> 操作,对类的成员变量赋值

class A{
    public:
    int x;
} a;

void func_c1()
{
    a.x = 1;
}

void func_c2()
{
    (&a)->x = 1;
}

在这里插入图片描述

总结

1、指针操作不是指针变量的专利,普通变量甚至立即数也可以做指针(* 、->)操作
在这里插入图片描述
注意不能出现下面的表达式,因为&a在这里是常量,不能单独出现在等式左边,同时要注意引用&与取地址&的区别,参考:指针变量的传值、传址和传引用

&a = (int*)0x1234

也不要出现下面的表达式,很显然 " * " 的操作数必须是指针

* 0x1234 = 1

2、计算机的世界里面,万物皆有地址,所以万物皆可指针,你既可以循规蹈矩通过变量名或规定的函数接口读写变量,也可能无视规则,通过指针操作,随意随时随地的读写变量
3、除了0x1234,指针操作可以读写任意的内存地址,除了内存管理单元MMU,没人能制止这种读写行为,这也是早期 “游戏修改器” 的工作原理
在这里插入图片描述
在这里插入图片描述

最后

正是指针操作的灵活性,让他成为大神和黑客的最爱,很多大神仅仅通过一个栈变量(a)的地址,配合指针操作,就可以试探、回溯出整个函数的调用轨迹。同时指针操作的不可控性也是大规模编程的噩梦,试想一下,你得到了某个“私有变量”的内存地址,就意味着你可以通过指针操作不受任何限制的读写这个变量,这时,你就不会再理会它“禁止访问”的私有属性了,你也不再愿意循规蹈矩的通过成员函数来读写它。

所以暴露任何数据、函数的内存地址都是巨大的风险,因为这些地址都可以用来做违规、不受控的指针操作。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只嵌入式爱好者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值