- 发现问题
- 问题分析
- 示例代码
发现问题
今天,在阅读Linux内核中关于socket的源代码时,遇到了下面一段代码:
struct proto_ops {
int family;
struct module *owner;
int (*release) (struct socket *sock);
int (*bind) (struct socket *sock,
struct sockaddr *myaddr,
int sockaddr_len);
int (*connect) (struct socket *sock,
struct sockaddr *vaddr,
int sockaddr_len, int flags);
int (*socketpair)(struct socket *sock1,
struct socket *sock2);
int (*accept) (struct socket *sock,
struct socket *newsock, int flags);
int (*getname) (struct socket *sock,
struct sockaddr *addr,
int *sockaddr_len, int peer);
unsigned int (*poll) (struct file *file, struct socket *sock,
struct poll_table_struct *wait);
int (*ioctl) (struct socket *sock, unsigned int cmd, unsigned long arg);
int (*listen) (struct socket *sock, int len);
int (*shutdown) (struct socket *sock, int flags);
int (*setsockopt)(struct socket *sock, int level,
int optname, char __user *optval, int optlen);
int (*getsockopt)(struct socket *sock, int level,
int optname, char __user *optval, int __user *optlen);
int (*sendmsg) (struct kiocb *iocb, struct socket *sock,
struct msghdr *m, size_t total_len);
int (*recvmsg) (struct kiocb *iocb, struct socket *sock,
struct msghdr *m, size_t total_len,
int flags);
int (*mmap) (struct file *file, struct socket *sock,
struct vm_area_struct * vma);
ssize_t (*sendpage) (struct socket *sock, struct page *page,
int offset, size_t size, int flags);
};
在这段代码中,我们注意到proto_ops结构体的成员包括下面这样的成员变量:
int (*release) (struct socket *sock);
这边是函数指针作为结构体成员变量的使用方法。
问题分析
首先,我们对C和C++中结构体以及C++类的区别进行一些说明:
C中的结构体和C++中结构体的不同之处:
在C中的结构体只能自定义数据类型,结构体中不允许有函数;
而C++中的结构体可以加入成员函数。
C++中的结构体和类的异同:
相同之处:
结构体中可以包含函数;也可以定义public、private、protected数据成员;定义了结构体之后,可以用结构体名来创建对象。但C中的结构体不允许有函数;也就是说在C++当中,结构体中可以有成员变量,可以有成员函数,可以从别的类继承,也可以被别的类继承,可以有虚函数。
不同之处:
结构体定义中默认情况下的成员是public,而类定义中的默认情况下的成员是private的。类中的非static成员函数有this指针,(struct中没有是错误的,一直被误导啊,经过测试struct的成员函数一样具有this指针),类的关键字class能作为template模板的关键字,而struct不可以。
实际上,C中的结构体只涉及到数据结构,而不涉及到算法,也就是说在C中数据结构和算法是分离的,而到C++中一类或者一个结构体可以包含函数(这个函数在C++我们通常中称为成员函数),C++中的结构体和类体现了数据结构和算法的结合。
因此,我们在阅读纯C代码时,应该注意代码中使用函数指针成员变量来等效地实现成员函数过程。
示例代码
这里,我们使用一段代码来对函数指针成员进行相关说明:
#include <stdio.h>
#include <stdlib.h>
int func1(int n)
{
printf("func1: %d\n", n);
return n;
}
int func2(int n)
{
printf("func2: %d\n", n);
return n;
}
int main()
{
int (*a[2])(int);
a[0] = func1;
a[1] = func2;
a[0](1);
a[1](2);
return 0;
}
我们注意上面代码中的
int (*a[2])(int);
在这句代码中,我们定义了这样一个数组:
数组保存指针,什么样的指针呢?
形如 int func(int input) 的 func函数指针,形参为int变量,返回int变量。
因此,数组保存的是形参为单一int变量和返回值为int值得函数指针。
现在,我们定义了这样一个数组,然后
a[0] = func1;
a[1] = func2;
由于我们在main函数前声明和定义了func1和func2两个函数(这两个函数满足前面所提及的函数条件),这时,我们便可以使用这两个函数指针赋值函数指针数组。
然后,我们便可以使用数组成员来实现函数调用:
a[0](1);
a[1](2);
最终结果为: