最近在使用libusb做USB驱动,编写代码的时候发现了一段有趣的代码
typedef struct libusb_device libusb_device;
而这个结构体是没有定义的,在我做出如下定义时编译器会报错: error C2079: “dev”使用未定义的 struct“CMW7300ISPTOOLDlg::OnBnClickedButton1::libusb_devic”
struct libusb_devic dev;
而定义为struct libusb_devic* dev;则不会报错,这是为什么呢?
网络搜索看到说这个属于不完全类型,typedef struct libusb_device libusb_device;这断代码相当于申明了一个结构体libusb_device,但是没有实际定义,类似于C语言的extern int A;在不使用申明的变量时,编译器是不会报错的,但是如果要使用的话,就需要先定义变量,比如要使用给A赋值2,就需要用int A = 2;直接使用A = 2编译器就会报错。同样的对于不完全定义的结构体typedef struct libusb_device libusb_device;而言也是一样的,不能直接定义struct libusb_devic dev;这样定义的话编译器不知道结构体的libusb_devic的大小,不知道开辟多少内存给变量,所以会报错,但是如果用struct libusb_devic* dev;就没问题了,因为这样定义的是一个指针,对于编译器而言,指针的大小是确定的(32位)4字节。
这里又出现一个新问题,这样定义之后在使用这个结构体的时候还是需要先定义如下结构体:
struct libusb_devic
{
若干变量;
}
那么这个不完全类型的意义何在呢?后来发现主要是封装时使用,当我们不希望别人访问和修改结构体内容的时候,我们就可以将结构体的定义封装成库,那么别人调用库的时候只能使用不完全类型作为接口,这样就没法访问结构体成员了,更不能修改结构体内容了。比如如下代码
ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx,
libusb_device ***list);
这就是libusb库中的一个函数,其参数libusb_device ***list是个封装在库里面的结构体,当我们要调用这个函数的时候,就需要先定义一个不完全变量struct libusb_device** device_list;,再调用函数libusb_get_device_list(NULL, &device_list);
这是我们是无法通过device_list->menber的方式访问结构体成员的,整个结构体对于用户来说就是一个黑匣子。