关于不完全类型的认识

最近在使用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的方式访问结构体成员的,整个结构体对于用户来说就是一个黑匣子。

张贴在2