欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

理解(*(void(*)())0)();

程序员文章站 2022-05-01 10:38:08
...
先说一下强制转换,可以跳过。例子:
#include <stdio.h>
#include <stdint.h>
int main()
{
    uint16_t a = 0xA5A1;
    uint8_t   b;
    b = (uint8_t)a;    // 16位强制转换为8位
    printf("b=0x%X",b); 
}

a是16位,b是8位,将a进行一次强制转换的结果给b。
我这里的输出结果是
b=0xA1
---------------------------------------正文----------------------------------------

include <stdio.h>

void funa(void)
{
	printf("funa is called\n");
}

int main()
{
	void (*p)();	// 定义一个函数指针
	p=funa;		    // p中存放funa函数地址 
	(*p)();		    // 运行funa 
	printf("0x%X",&funa); // 打印funa函数的地址 
	return 0;	
}


我这里执行之后得到的结果是
funa is called
0x401530


第一行表示funa函数已经执行
第二行表示funa函数的地址为0x401530(在不同机器不同时间结果可能都不同)

以这里的结果为例,此时将上述代码的第11、12行改为
p=0x401530;
(*p)();

运行结果是相同的。

但是将11、12行合并为:
(*0x401530)();
编译器会报错。

也就是说,我们需要将 "0x401530"强制转换为函数地址
参照最开始的强制转换,这里的格式应该大体是这样的:
(*(_______)0x401530)();

接下来只需要考虑下划线里该填什么了
参照之前的
void (*p)();     // 定义一个函数指针
我们可以知道,下划线里应该写
void (*)()

那么结果就出来了,这里要想将11、12行合并为一句,只需要这么写:
(* (void (*)())0x401530)();

我这里修改之后的最终程序为:
#include<stdio.h>

void funa(void)
{
	printf("funa is called\n");
}

int main()
{
	(*(void(*)())0x401530)();	// 运行位于0x401530地址处的funa函数 
	printf("0x%X",&funa); 		// 打印funa函数的地址 
	return 0;	
} 

输出和之前是完全相同的。

--------------------------------------归题--------------------------------------
如果我们需要运行位于0地址处的函数(或者是从0地址处开始运行)
只需把上面的0x401530改成0即可
也就是
(*(void(*)())0)();
---------------------------------------拓展----------------------------------------
如果真的理解之后,可以配合typedef使用。
之前的例子可以这样写
#include<stdio.h>
typedef void (*funcptr)();    // 为函数指针类型定义别名funcptr

void funa(void)
{
	printf("funa is called\n");
}

int main()
{
	(*(funcptr)0x401530)();	// 运行位于0x401530地址处的funa函数 
	printf("0x%X",&funa); 	// 打印funa函数的地址 
	return 0;	
} 


参考资料: <C的陷阱与缺陷> 2.1章 Andrew Koenig著