当前位置: 首页 > news >正文

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;
}

 

相关文章:

  • libusb源码学习:几个函数加载的宏(windows)
  • MCU_如何通过硬件VID 查找生产厂家
  • MCU_WireShark USB抓包内容解析
  • MCU_Wireshark USB 抓包过滤(抓特定端口地址)
  • STM32F4xx usb库源码详解 custom HID
  • STM32F4xx usb库源码详解:HAL_PCDEx_SetRxFiFo 和 HAL_PCDEx_SetTxFiFo
  • Libuv 1.34.2 源码详解 ---- 以uvCat为例讲解
  • 步进电机的细分驱动中1-2相, W1-2相, 2W1-2相, 4W1-2相 表示什么意思?
  • MCU_关于STM32Fxxx中断EXTI产生时多次(两次)进入中断的原因
  • MCU_通过windows串口API控制RTS和DTR
  • MCU_STM32的HAL库中的宏DMA_FLAG_TCIF0_4/DMA_FLAG_TCIF1_5/DMA_FLAG_TCIF2_6/DMA_FLAG_TCIF3_7
  • LWIP_TCP如何理解数据发送,何时使用tcp_recved函数
  • MCU_使用STM32CUBEMX配置STM32F107/407 RMII-ETHERNET要注意的细节:PHY Address和MCO时钟
  • MCU_STM32CUBEMX v5.5.0的一个BUG:ethernetif_input引起进入HardFault_Handler
  • MCU_STM32CUBEMX配置生成CAN2的初始化代码的修改
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • github指令
  • Nodejs和JavaWeb协助开发
  • PermissionScope Swift4 兼容问题
  • python 装饰器(一)
  • rc-form之最单纯情况
  • scrapy学习之路4(itemloder的使用)
  • Web Storage相关
  • Yii源码解读-服务定位器(Service Locator)
  • 发布国内首个无服务器容器服务,运维效率从未如此高效
  • 检测对象或数组
  • 力扣(LeetCode)56
  • 扑朔迷离的属性和特性【彻底弄清】
  • 通过npm或yarn自动生成vue组件
  • 一个6年java程序员的工作感悟,写给还在迷茫的你
  • 用element的upload组件实现多图片上传和压缩
  • 运行时添加log4j2的appender
  • 自定义函数
  • 【干货分享】dos命令大全
  • C# - 为值类型重定义相等性
  • ​ubuntu下安装kvm虚拟机
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • ​油烟净化器电源安全,保障健康餐饮生活
  • ###C语言程序设计-----C语言学习(6)#
  • $jQuery 重写Alert样式方法
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (多级缓存)多级缓存
  • (附源码)ssm户外用品商城 毕业设计 112346
  • (论文阅读30/100)Convolutional Pose Machines
  • (论文阅读笔记)Network planning with deep reinforcement learning
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (四)Linux Shell编程——输入输出重定向
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (一)【Jmeter】JDK及Jmeter的安装部署及简单配置
  • (原創) 如何解决make kernel时『clock skew detected』的warning? (OS) (Linux)
  • (转) Android中ViewStub组件使用
  • .gitignore文件---让git自动忽略指定文件
  • .NET 设计一套高性能的弱事件机制
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值
  • .Net语言中的StringBuilder:入门到精通