概念
函数指针:首先它是一个指针,一个指向函数的指针,在内存空间中存放的是函数的地址;
引入
#include <stdio.h>
void test()
{
printf("hehe\n");
}
int main()
{
printf("%p\n", test);
printf("%p\n", &test);
//函数名是等于函数地址,所以两个打印函数结果一样
return 0;
}
这个代码输出的结果是一样的,输出的是两个地址。因为,函数名是等于函数地址。
那我们的函数的地址要想保存起来,怎么保存?直接调用下面这句:
void (*pfun)(void) = test;
(*pfun)(); //test(); 或者 pfun();
pfun1先和*结合,说明pfun1是指针,指针指向的是一个函数,指向的函数无参数,返回值类型为void
上面这个是无参例子,下面讲有参例子 :
#include <stdio.h>
#include <string.h>
int test(const char* str)
{
printf("test()\n");
return 0;
}
int main()
{
//函数指针 - 也是一种指针,是指向函数的指针
printf("%p\n", test);
printf("%p\n", &test);
//函数名是等于函数地址,所以两个打印函数结果一样
int (* pf)(const char*) = test;
(*pf)("abc");
//pf 和 test 等价,则(*pf)("abc"); 可以写成 test("abc"); 或者 pf("abc");
return 0;
}
//这里abc是参数,可以随便给,只要是字符型就可以。因为这里没有具体参数调用
通过上面两个简单案例,我们可以总结函数指针的使用模板,如下:
int Add(int x)
{
return 0;
}
int main()
{
int (*pf)(int) = &Add;//函数指针定义,返回值类型和参数类型与函数Add()相同
(*pf)(int类型);
}
其他陷阱
注 :来源《C陷阱和缺陷》
(*(void (*)())0)(); //代码1
void (* signal(int,void( * )( int ) ) )(int); //代码2
(*(void (*)())0)();
在代码1里面,数字0前面的部分:void(*)()怎么理解?如果我们写成void(*p)()呢?
可以这么理解:
-
void
:这是函数指针p
所指向的函数的返回类型。在这里,void
表示该函数没有返回值。 -
(*p)
:这部分声明了一个指针变量p
,它可以指向一个函数。*
是指针声明的一部分,表示p
是一个指针。 -
()
:这一对括号表示指针p
所指向的函数不接受任何参数。如果要指向接受参数的函数,括号内会包含参数列表。
综合起来,void(*p)()
表示一个指向不接受任何参数并且没有返回值的函数的指针。你可以将这个指针指向相应类型的函数,然后通过该指针调用该函数。
则void(*)()理解:void()() 表示函数指针类型,类似于int* char*这些类型一样
下一步理解:( void()() )0
-
(void()())
:这是一个类型转换表达式,试图将一个整数值0
转换为一个函数指针类型。但是,(void()())
不是有效的类型转换,因为它没有指定要将整数值转换为哪种函数类型。如(int)3.14 -
0
:这是一个整数字面值,表示零。
总结:这里是一次函数调用,调用的是0作为地址处的函数。调用0地址处的这个函数。
再理解 :* ( void()() )0
*
:这是一个解引用运算符。它用于访问指针所指向的对象或函数
-
(void()())0
尝试将整数0
转换为一个函数指针类型,但由于没有明确的函数指针类型,这通常会导致编译错误。 -
*
解引用运算符试图访问一个函数指针,但由于前面的转换通常是非法的,这也会导致编译错误。
所以代码1,可以这样理解:
(void(*)())
表示一个函数指针类型,该指针指向一个不接受任何参数且没有返回值(void
)的函数。然后,( *(void(*)())0 )
尝试将整数常量 0
转换为这种函数指针类型,但通常这是不合法的,因为整数不能直接转换为函数指针类型。
接着,( *(void(*)())0 )( )
看起来像一个函数调用表达式,它试图通过解引用一个无效的函数指针来调用一个函数。这也是不合法的,因为在这种情况下,函数指针是无效的(尝试将整数转换为函数指针是不合法的操作)。
代码1归纳
void (* signal(int,void( * )( int ) ) )(int);
这是一个 C 语言中的函数声明,表示 `signal` 是一个函数,它接受两个参数并返回一个函数指针。让我逐步解释它的各个部分:
1. `signal`:这是函数的名称,表示函数的标识符是 `signal`。
2. `int`:这是函数 `signal` 的第一个参数,它是一个整数类型。
3. `void(*)(int)`:这是函数 `signal` 的第二个参数,它是一个指向函数的指针类型。具体来说,它是一个指向接受一个整数参数并且没有返回值的函数的指针类型。
4. `(* signal(int, void(*)(int)))`:这部分表示函数 `signal` 接受两个参数,一个整数和一个函数指针,然后返回一个函数指针。
5. `void(*)(int)`:最后,这部分表示 `signal` 函数返回的函数指针的类型,它是一个指向接受一个整数参数并且没有返回值的函数的指针类型。
综合起来,这个函数声明的含义是:`signal` 是一个函数,它接受一个整数参数和一个指向接受整数参数并且没有返回值的函数的指针参数,然后返回一个指向类似函数的指针,这个函数指针接受一个整数参数并且没有返回值。
这种类型的函数通常用于设置信号处理程序,其中第一个参数是信号的编号,第二个参数是一个函数指针,指向在接收到特定信号时要执行的处理程序。函数 `signal` 返回的函数指针通常用于保存先前的信号处理程序的引用,以便以后可以还原它。