最近在看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