今天,在閱讀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
#include
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);
最終結果為: