转载请注明原地址:http://blog.csdn.net/oyhb_1992/article/details/76975284
typedef int(init_fnc_t) (void)和 typedefint(*init_fnc_t) (void)函数类型和函数指针的区别
函数名概念明确:
函数名本质就是反汇编后的一个标号。这个标号就指明了函数在内存中的首地址,函数内容就是反汇编后的函数参数传给寄存器或入栈,还可能有一些堆空间的分配,然后是函数的代码段的指令。所以函数名的本质其实是汇编代码的入口地址,调用函数就是movpc,func(函数地址); 所以对函数名(反汇编)内存地址取值*init_fnc_t()是没有意义的。
typedef int(init_fnc_t) (void);
就是对一个 int (void)类型的函数类型进行取别名init_fnc_t。 我们可以利用这个别名进行创建这个类型的函数对象,它的主要功能也就是定义一个函数指针变量:指向一个函数。要明确的是init_fnc_t函数类型是没有什么作用的,它必须init_fnc_t* 才可以用来指向一个init_fnc_t函数类型(参数为空,返回值为int)的变量。
init_fnc_t * init_fnc_ptr;以及指针用来指向一个函数
init_fnc_t ** init_fnc_ptr;二级指针用来指向一个函数指针数组
通俗来讲,函数名是一个地址,而我们调用的时候**()中**也是用地址值。所以我们通常用一个函数指针p指向一个函数名**,调用的时候p()就可以,*p()反倒是错的,前面函数名概念明确里就讲过函数名(反汇编)内存地址取值是没有意义的。
typedef int(*init_fnc_t_p)(void);
这里是一个函数的指针。如果某个函数的类型和这个函数一样的,那么可以将这个函数的指针指向该函数。
#include <stdio.h>
int OutData(void)
{
return 10;
}
int main()
{
typedef int (init_fnc_t)(void);//函数类型取别名
typedef int (*init_fnc_t_p)(void);//函数类型指针(地址)取别名
init_fnc_t *MyFunction; //定义函数指针变量
init_fnc_t_p MyFunctionP; //定义函数指针变量
MyFunction= OutData; //函数地址OutData传给MyFunction变量,后面调用的时候//MyFunction()我们也不对这个地址取值
MyFunctionP = OutData;
printf("(init_fnc_t)(void) = %d \n",MyFunction());
printf("(*init_fnc_t_p)(void) = %d \n",MyFunctionP());
return 0;
}
接下来看一个Uboot里的较复杂的函数指针用法:
/************************************************************************
*Initialize Environment use
*
* Weare still running from ROM, so data use is limited
*/
int env_init(void)
{
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid= 0;
return(0);//返回0代表函数执行成功
}
typedef int (init_fnc_t)(void);
/************************************************************************
*Initialization sequence *
***********************************************************************/
/*定义了函数指针数组,里面数组元素存的是函数地址,调用的时候init_sequence[*] ()就是跳到这个地址处执行函数,* init_sequence[*] ()调用是错误的*/
init_fnc_t*init_sequence[] = {
#if defined(CONFIG_BOARD_EARLY_INIT_F)
board_early_init_f, /* Call board-specific init code early.*/
#endif
env_init,
serial_init,
console_init_f,
display_options,
checkcpu,
checkboard,
NULL, /* Terminate this list*/
};
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;
/*分成两部分来看init_fnc_t *表示函数指针类型,*init_fnc_ptr 是定义的一个函数指针变量,init_sequence[*] =*init_fnc_ptr 应该相等,都是表示一个函数的内存地址*/
char*s;
#if defined(CONFIG_VFD) ||defined(CONFIG_LCD)
unsignedlong addr;
#endif
/*Pointer is writable since we allocated a register for it */
/*_armboot_start是uboot下载到内存中的地址值,减掉CONFIG_SYS_MALLOC_LEN和gd_t结构体大小就是gd变量的地址*/
/*为gd指针变量分配内存*/
gd= (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
/*compiler optimization barrier needed for GCC >= 3.4 */
__asm____volatile__("": : :"memory");
/*清零gd结构体变量的内存*/
memset((void*)gd, 0, sizeof (gd_t));
/*注意:内存上gd_t结构体的后面存的是bd_t结构体*/
gd->bd= (bd_t*)((char*)gd - sizeof(bd_t));
memset(gd->bd, 0, sizeof (bd_t));
gd->flags|= GD_FLG_RELOC;
/*_armboot_start=_start*/
/*得到uboot代码在内存中的存储区域大小*/
monitor_flash_len= _bss_start - _armboot_start;
for (init_fnc_ptr = init_sequence; *init_fnc_ptr;++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) { //*init_fnc_ptr)表示一个函数的地址
//*init_fnc_ptr==NULL退出循环;++init_fnc_ptr指向下一个数组元素 hang ();
/* *init_fnc_ptr是看数组里的成员值是否是NULL,*init_fnc_ptr()中()表示跳到这个函数入口地址处执行函数*/
}
}
什么理解记忆也比不上一张图