最近在看UVC摄像头驱动,发现了这几段代码:
for (j = 0; j < npackets; ++j) {
urb->iso_frame_desc[j].offset = j * psize;//iso是实时的意思
urb->iso_frame_desc[j].length = psize;
}
跟踪iso_frame_desc ,发现了0数组。
(在linux-3.4.20\include\linux\Usb.h里)
struct urb {
/* private: usb core and host controller only fields in the urb */
struct kref kref; /* reference count of the URB */
void *hcpriv; /* private data for host controller */
atomic_t use_count; /* concurrent submissions counter */
atomic_t reject; /* submissions will fail */
int unlinked; /* unlink error code */
/* public: documented fields in the urb that can be used by drivers */
struct list_head urb_list; /* list head for use by the urb's
* current owner */
struct list_head anchor_list; /* the URB may be anchored */
struct usb_anchor *anchor;
struct usb_device *dev; /* (in) pointer to associated device */
struct usb_host_endpoint *ep; /* (internal) pointer to endpoint */
unsigned int pipe; /* (in) pipe information */
unsigned int stream_id; /* (in) stream ID */
int status; /* (return) non-ISO status */
unsigned int transfer_flags; /* (in) URB_SHORT_NOT_OK | ...*/
void *transfer_buffer; /* (in) associated data buffer */
dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */
struct scatterlist *sg; /* (in) scatter gather buffer list */
int num_mapped_sgs; /* (internal) mapped sg entries */
int num_sgs; /* (in) number of entries in the sg list */
u32 transfer_buffer_length; /* (in) data buffer length */
u32 actual_length; /* (return) actual transfer length */
unsigned char *setup_packet; /* (in) setup packet (control only) */
dma_addr_t setup_dma; /* (in) dma addr for setup_packet */
int start_frame; /* (modify) start frame (ISO) */
int number_of_packets; /* (in) number of ISO packets */
int interval; /* (modify) transfer interval
* (INT/ISO) */
int error_count; /* (return) number of ISO errors */
void *context; /* (in) context for completion */
usb_complete_t complete; /* (in) completion routine */
struct usb_iso_packet_descriptor iso_frame_desc[0];
/* (in) ISO ONLY */
};
数组元素为0,表示struct usb_iso_packet_descriptor iso_frame_desc[0] 不占内存。那么内核代码这样写的意义是什么呢?
而且为何上面的UVC驱动代码urb->iso_frame_desc[j]里的数组元素不为0 ? ?
在结构体中,iso_frame_desc是一个数组名;但该数组没有元素;该数组的真实地址紧随结构体urb之后,而这个地址就是结构体后面数据的地址(如果给这个结构体分配的内容大于这个结构体实际大小,后面多余的部分就是这个iso_frame_desc的内容);这种声明方法可以巧妙的实现C语言里的数组扩展。
对于 urb->iso_frame_desc[j] 的使用,表明数组iso_frame_desc已经被分配了内存,那么在哪里分配的呢?
是通过 struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) 来分配的,数组iso_frame_desc的大小为iso_packets 。
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
{
struct urb *urb;
urb = kmalloc(sizeof(struct urb) +
iso_packets * sizeof(struct usb_iso_packet_descriptor),
mem_flags);
if (!urb) {
printk(KERN_ERR "alloc_urb: kmalloc failed\n");
return NULL;
}
usb_init_urb(urb);
return urb;
}
今天看linux中usb部分的代码,看到如下的数据结构:
struct urb
{
......
struct iso_packet_descriptor iso_frame_desc[0];
};
觉得很差异,0个元素的数组?
google了一下相关内容:
只有0个元素的数组在某些情况下是很有用处的,在WINDOWS的头文件里经常有这样的情况出现。例如:
typedef struct _TestStruct_
{
int nItemCount;
ANY_TYPE item[0];
}TEST_STRUCT;
此时,用sizeof(TEST_STRUCT)得到的数值为4,即sizeof(int),后面的在结构体ANY_TYPE里是不占空间的。如果我们要分配100个item,可以这样:
TEST_STRUCT * pTestStruct = (TEST_STRUCT *)malloc(sizeof(TESTSTRUCT) + sizeof(ANT_TYPE) * 100);
在要访问第n个item时,可以这样来访问 pTestStruct-> item[n],是不是很方便?
参考:https://bbs.csdn.net/topics/80291402