libusb源碼學習:list_entry

USB開發涉及到libusb,看了下源碼,現在已經到了1.0.23版;全部用的C,編譯器和平臺的普適性相對比較強;

其中的list_head作爲關鍵鏈表,也是各個鏈接結構的成員(member)變量。而利用這個成員變量完成各個結構鏈接,涉及到幾個很有意思的宏,其中包括list_entry,list_for_each_entry,這種用法和我們最普通的用法有點區別:在C ++中,通常我用標準std::list, std::vector實現;在C中,我們往往直接使用結構自自身的指針來完成鏈接,而不是使用這種成員鏈接指針(list_head)。

寫了個list_entry應用原理的解析,用3種完全等價的方式找到:dev->session_data == 2

#include <iostream>

struct list_head {
    struct list_head* prev, * next;
};

/* Get an entry from the list
 *  ptr - the address of this list_head element in "type"
 *  type - the data type that contains "member"
 *  member - the list_head element in "type"
 */
#define list_entry(ptr, type, member) \
	((type *)((uintptr_t)(ptr) - (uintptr_t)offsetof(type, member)))


#define list_first_entry(ptr, type, member) \
	list_entry((ptr)->next, type, member)

 /* Get each entry from a list
  *  pos - A structure pointer has a "member" element
  *  head - list head
  *  member - the list_head element in "pos"
  *  type - the type of the first parameter
  */
#define list_for_each_entry(pos, head, member, type)			\
	for (pos = list_entry((head)->next, type, member);		\
		 &pos->member != (head);				\
		 pos = list_entry(pos->member.next, type, member))

#define list_for_each_entry_safe(pos, n, head, member, type)		\
	for (pos = list_entry((head)->next, type, member),		\
		 n = list_entry(pos->member.next, type, member);	\
		 &pos->member != (head);				\
		 pos = n, n = list_entry(n->member.next, type, member))

#define list_empty(entry) ((entry)->next == (entry))

struct libusb_device {
	int refcnt;	
	uint8_t bus_number;
	uint8_t port_number;
	struct libusb_device* parent_dev;
	uint8_t device_address;
	uint8_t num_configurations;
	
	struct list_head list;
	unsigned long session_data;	
};

libusb_device* list_entry_func(list_head* ptr) {
	uintptr_t upt = offsetof(libusb_device, list);
	upt = (uintptr_t)(ptr) - upt;
	return (libusb_device*)(upt);
}

int main() {
	libusb_device ld1;
	libusb_device ld2;
	libusb_device ld3;
    ld1.list.next = &ld2.list;
    ld2.list.prev = &ld1.list;
    ld2.list.next = &ld3.list;
    ld3.list.prev = &ld2.list;
	ld1.session_data = 1;
	ld2.session_data = 2;
	ld3.session_data = 3;

	struct list_head usb_devs;
	usb_devs.next = &ld1.list;
	usb_devs.prev = &ld3.list;

	struct libusb_device* dev;
	struct libusb_device* ret = NULL;
	
//#define list_entry(ptr, type, member) \
	//((type *)((uintptr_t)(ptr) - (uintptr_t)offsetof(type, member)))
//#define list_first_entry(ptr, type, member)               \
	//list_entry((ptr)->next, type, member)
//#define list_for_each_entry(pos, head, member, type)		\
	//for (pos = list_entry((head)->next, type, member);		\
	//	 &pos->member != (head);				                \
	//	 pos = list_entry(pos->member.next, type, member))

	list_for_each_entry(dev, &usb_devs, list, struct libusb_device)
		if (dev->session_data == 2) {
			std::cout << "found the member in the list: 0 !" << std::endl;
			break;
		}
	
	for (dev = list_entry_func(usb_devs.next);
		&dev->list != &usb_devs;
		dev = list_entry_func(dev->list.next)) {
		if (dev->session_data == 2) {
			std::cout << "found the member in the list: 1 !" << std::endl;
			break;
		}
	};
	
	for (dev = list_entry(usb_devs.next, libusb_device, list);
		&dev->list != &usb_devs;
		dev = list_entry(dev->list.next, libusb_device, list))
		if (dev->session_data == 2) {
			std::cout << "found the member in the list: 2 !" << std::endl;
			break;
		}
	return 0;
}

 

發佈了184 篇原創文章 · 獲贊 110 · 訪問量 40萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章