Raw OS源码中的raw_list_entry(node, type, member)分析

文章目录

说明

在看Raw OS的源代码时,在raw_list.h里面有如下宏定义:

#define raw_list_entry(node, type, member)    ((type *)((RAW_U8 *)(node) - (RAW_U32)(&((type *)0)->member)))

乍一看这个宏定义有点复杂,其实只要按部就班的分析,是很好理解的。我们看调用此宏定义时传进来的形参是什么,全局搜索此宏定义,发现在

void tick_list_update(void)
{
    
    
	...
	RAW_TASK_OBJ            *p_tcb;
	LIST                    *iter;
	...
	p_tcb =  raw_list_entry(iter, RAW_TASK_OBJ, tick_list);
	...
	...
}

函数中调用了该宏定义,其中RAW_TASK_OBJ结构体定义如下:

typedef struct 
{
    
    
	RAW_VOID                 *task_stack;

	#if (CONFIG_RAW_MPU_ENABLE > 0)
	RAW_MPU_SETTINGS         mpu_settings;
	#endif

	LIST                     task_list;
	...
	...
} RAW_TASK_OBJ;

下面我们开始分析该宏定义的功能:

分析

首先我们分析使用该宏定义时的形参和返回值,我们发现返回值赋值给了p_tcb,而p_tcb是RAW_TASK_OBJ类型的指针,因此我们可以判断该宏定义返回的是RAW_TASK_OBJ类型结构体的地址。
分析形参,第一个形参是iter,类型是LIST循环链表;第二个形参是RAW_TASK_OBJ,其是结构体类型说明;第三个形参是tick_list,其是RAW_TASK_OBJ结构体中一个LIST链表的名称。
分析宏定义结构,

#define raw_list_entry(node, type, member)    ((type *)((RAW_U8 *)(node) - (RAW_U32)(&((type *)0)->member)))

发现(type *)强制类型转换,即将一个东西强制转换为type指针类型,而type刚好是输入形参RAW_TASK_OBJ,则(type *)后面大括号中的东西应该是一个其他类型的指针。分析大括号中代码:

((RAW_U8 *)(node) - (RAW_U32)(&((type *)0)->member)))

其中node是传入的iter,一个LIST类型的指针,将该指针强制转换成了RAW_U8 类型的指针。然后该指针减去了一坨奇怪的东西后,就运行结束了。我们发现,一个LIST类型的指针,减去一个值后,就变为了RAW_TASK_OBJ类型的指针。
我们看RAW_TASK_OBJ定义,发现其中有LIST task_list。假设(RAW_U8 *)(node)的地址是RAW_TASK_OBJ中的task_list,则task_list减去在RAW_TASK_OBJ中的偏移量,就可以得到task_list所在结构体的首地址。因此,我们可以初步断定(RAW_U8 *)(node)后面减去的一坨就是task_list在RAW_TASK_OBJ结构体中的偏移量。
下面我们来分析后面的一坨是怎么实现的:

(RAW_U32)(&((type *)0)->member))

type*是输入的结构体类型RAW_TASK_OBJ,将地址0强制转换为RAW_TASK_OBJ类型,然后取task_list在该结构体中的地址。因为RAW_TASK_OBJ是强制从地址0开始的,那么task_list所在的地址也就是相对于地址0的绝对地址,刚好等于task_list在RAW_TASK_OBJ中的偏移量。因此,后面这一坨其实就是算结构体中某个变量在结构体中的偏移量的。

猜你喜欢

转载自blog.csdn.net/wcc243588569/article/details/117754931