同一个数可以通过不同的方式表达出来,对于函数的访问,变量的赋值除了直接对变量赋值以外,还可以通过绝对内存地址进行参数赋值与函数调用。
(1) 通过地址修改变量的值
int x; int *p; printf("%x\n",&x); p=(int *)0x0012ff60; *p = 3; printf("%d\n",x); |
程序的输出结果为:
12ff60 3 |
程序首先输出变量x所在地址为十六进制的0x12ff60(本来应该为8位的十六进制数,高位为0则省略掉),然后定义一个指针变量,让它指向该地址,通过指针变量的值来修改变量x的值。
示例代码:
int *ptr=(int*)0xa4000000; *ptr=0xaabb; printf("%d\n",*ptr); |
以上程序会崩溃,因为这样做会给一个指针分配一个随意的地址,很危险,所以这种做法是不允许的。
(2) 通过地址调用函数的执行
#include <iostream> using namespace std; typedef void(*FuncPtr)() ; void p() { printf("MOP\n"); } int main() { void (*ptr)(); p(); printf("%x\n",p); ptr = (void (*)())0x4110f0; ptr();//函数指针执行 ((void (*)())0x4110f0)(); ((FuncPtr)0x4110f0)(); return 0; } |
程序执行结果如下:
MOP 4110f0 MOP MOP MOP |
首先定义一个ptr的函数指针,第一次通过函数名调用函数,输出Mop,打印函数的入口地址,函数的入口地址为4110f0。然后给函数指针ptr赋地址值为p的入口地址,调用ptr,输出Mop。接着的过程是不通过函数指针直接执行,仍然使用p的入口地址调用,输出为MOP。最后是通过typedef调用的直接执行。
函数名称、代码都是放在代码段的,因为是放在代码段,每次会跳到相同的地方,但参数会压栈,所以函数只根据函数名来获取入口地址,与参数和返回值无关。无论参数和返回值如何不同,函数入口地址都是一个地方。
对以下程序进行分析如下:
#include <stdio.h> int p(int a,int b) { return 3; } int main() { printf("%x\n",p); int a = p(2,3); printf("%d\n",p); int b = p(4,5); printf("%x\n",p); return 0; } |
程序输出结果如下:
411159 4264281 411159 |
十六进制的411159转换成十进制的值为4264281。程序中打印的p的入口地址,无论p是否调用函数,入口地址都没有改变。
分析如下代码:
#include <stdio.h> int p(int a,int b) { return ((a>b)?a:b); } int main() { int (*ptr)(int ,int); ptr = (int (*)(int,int))0x411159; int c = ptr(5,6); printf("%d\n",c); return 0; } |
程序输出为
6 |
通过函数指针调用有返回值和参数的函数,不适用函数名,而是用函数入口地址调用。
函数存放在内存的代码区域内,也有地址,一个函数在编译时被分配一个入口地址,将这个入口地址称为函数的指针,函数的地址就是函数的名字。
函数指针不能指向不同类型或是带不同形参的函数。
参考链接:
(<<程序员面试笔试宝典>>官网)
方法一:
*(int *)0x6789 = 0x0080; //直接把0x0080赋值给地址为0x6789的单元
int m;m = *(int *)0x6789; //从地址为0x6789的单元取值赋给变量m---------------------------------------------------------------------------- 方法二:int *p, m;p = (int *)0x6789;*p = 0x0080;m = *p;
想让程序跳转到绝对地址是0x100000的代码去执行,应该怎么做?
网上有三种答案(本人没有验证):第一种: *((void (*)( ))0x100000 ) ( );第二种: ((void (*)())0x100000)() 或者 (*((void (*)())0x100000))() 源地址:第三种:typedef void (*func)(void); func f = (func)1000000; f();