C语言-函数指针void(*)(void),通用函数指针void(*)()

一、开始

在阅读代码的时候看到有一段代码,令人有点懵。

static void __near VECTOR_TABLE_04H(void){((void(*)(void))(*(__far unsigned long *)(FLASH_TABLE + 0x04 *2)))();}

看上去像是一个函数,调整一下位置,括号太多了。

static void __near VECTOR_TABLE_04H(void)
{
	(   ( void(*)(void) )   (*(__far unsigned long *)(FLASH_TABLE + 0x04 *2))     )    ();
}

__far与__near都是与编译器有关的参数,可以忽略。

首先看:( * (__far unsigned long *)(FLASH_TABLE + 0x04 *2))
这是单片机里常用的方式,先将一个值强制转化为unsigned long类型指针,再用 * 取值。

然后: void(*)(void)是函数指针,返回void,参数void。即把取出的值强制转化为函数指针。

最后:() ,就是起到调用函数的作用了。

二、而有的函数指针比较特殊

如int ( * )()或void ( * )()。可以使用任何函数类型,即未指明参数、返回int或void的函数作为通用函数指针。

测试代码
使用:chcp查看cmd的编码,936代码gbk。(可以使用命令:chcp 65001,暂时切换为UTF-8编码 )
在这里插入图片描述

注意:gcc编译的时候,后面加上-fexec-charset=gbk,不然可能中文打印乱码
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

void myfunc_void_void(void){ printf("This is myfunc_void_void\n");};
void myfunc_void_int(int t){printf("This is myfunc_void_int,input:%d\n",t);};
int myfunc_int_void(void){ printf("This is myfunc_int_void\n");}
int myfunc_int_int(int t){ printf("This is myfunc_int_int,input: %d\n",t);}

void myfunc_void_generalPointer(void* t){
printf("myfunc_void_generalPointer:is a int:%d \n",*(int*)t);
printf("myfunc_void_generalPointer:is a char:%c \n",*(char*)t);
//printf("func3:is a string:%s ?\n",(char*)t);
};

typedef void(*pointer_2_void_func_void)(void);
typedef void(*pointer_2_void_func_int)(int);

typedef int(*pointer_2_int_func_void)(void);
typedef int(*pointer_2_int_func_int)(int);

typedef void(*pointer_2_void_func_general)();
typedef int(*pointer_2_int_func_general)();

int main(int argc,char** argv){
	//取指针地址为值,再转换回去。
	printf("//取指针地址为值,再转换回去:\n");
	int value_func_address = (int)myfunc_void_void;
	pointer_2_void_func_void  p1  = ( void ( * )(void) ) value_func_address;
	p1();
		
	//用直接的方法,声明一个void通用函数指针
	printf("//用直接的方法,声明一个void通用函数指针:\n");
	void ( *gpv0 )() ;
	gpv0 = myfunc_void_void;
	gpv0();
	gpv0 = myfunc_void_int;
	gpv0(998);
	
	/*error example 错误例子
	pointer_2_int_func_void int_void_p1;
	pointer_2_int_func_int  int_int_p2;
	int_void_p1 = myfunc_int_int;
	int_int_p2  = myfunc_int_void;
	*/
		
	//用通用函数指针定义,void和int类型通用函数指针
	printf("//用通用函数指针定义,void和int类型通用函数指针:\n");
	pointer_2_void_func_general  gvp1;
	pointer_2_int_func_general   gip1;
	gvp1 = myfunc_void_void;
	gvp1(); int ts = 15;
	gvp1 = myfunc_void_generalPointer;
	gvp1(&ts);
	gip1 = myfunc_int_void;
	gip1();
	gip1 = myfunc_int_int;
	gip1(45);
	
	
	//函数参数是void*类型时:
	printf("//函数参数是void*类型时:\n");
	int a=14;
	char b='g';
	char* c="abs";
	myfunc_void_generalPointer(&a);
	myfunc_void_generalPointer(&b);
	//myfunc_void_generalPointer(c);
	
	return 0;
}

输出如图:
在这里插入图片描述

三、参考书籍

第四章-指针-4.13
问:通用指针类型是什么?当我把函数指针赋向void *类型的时候,编译通不过。
答:没有什么“通用指针类型”。void 指针只能保存对象(也就是数据)指针。将函数指针转换为void 指针是不可移植的。(在某些机器上,函数指针可能很大—–比任何数据指针都大。)但是,可以确保的是,所有的函数指针类型都可以相互转换,只要在调用之前转回了正确的类型即可。因此,可以使用任何函数类型(通常是int ()()或void ()(),即未指明参数、返回int或void的函数)作为通用函数指针。如果你需要一个既能容纳对象指针又能容纳函数指针的地方,可移植的解决方案是使用包含void *指针和通用函数指针(任何类型都可以)的联合。

第四章-指针-4.14
问:怎样在整型和指针之间进行转换?能否暂时把整数放入指针变量中,或者相反?
答:曾经有一段时间,可以确保能将指针转换为整数(尽管谁也不知道究竟是需要int还是long型),将整数转换为指针。同时可以确保指针在转换为(足够大的)整数及转换回来的时候值不会改变,而且转换(及任何映射)都不应该“让那些知道机器寻址结构的人感到惊奇”。换言之,有整数/指针转换的先例和支持,但这总是和机器相关的,因此不具可移植性。
而且总是需要显式的类型转换(但是就算你忘了转换,早期的编译器也几乎不会报警。)为了使C语言广泛地可实现,ANSI/ISO C标准削弱了这些早期的保证。指针到整数和整数到指针的转换变成了实现定义的(参见问题11.35),因此也就没有了指针和整数可以无需修改就相互转换的保证。
强制将指针转换为整数和将整数转换为指针从来都不是什么好的实践。当需要同时保存两种类型数据的存储结构的时候,使用联合是一个更好的办法。

更新:
书籍信息:《C Programming FAQs: Frequently Asked Questions》、《你必须知道的495个C语言问题(这中文翻译名称完全对不上,让人好找。。。)》 作者: Steve Summit 时间:1996
。。====
本书有网页版:https://c-faq.com/index.html


版权声明:本文为lsllll44原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。