C语言list头文件_freertos中的list.c和list.h文件详解

C语言list头文件_freertos中的list.c和list.h文件详解_第1张图片

小白理解 抛砖引玉 欢迎加v共同学习!!!加V请备注"Freertos "。备注:本系列均基于stm32cubeIDE,并非keilV5哦!!!

C语言list头文件_freertos中的list.c和list.h文件详解_第2张图片

FreeRTOS基本文件生成和说明

在Middleware下勾选Freertos,接口选择CMSIS_V1或CMSIS_V1,点击上方小齿轮重生成代码后,将在“project explorer->Middlewares->Third_Party->FreeRTOS->Source"目标下生成若干文件和文件夹。

(1):include文件夹、portable文件夹、CMSIS_RTOS或CMSIS_RTOS_V2文件夹(这两个文件加2选1,如果Freertos的接口选择为CMSIS_V1则为CMSIS_RTOS;否则为接口选择为CMSIS_V2则为CMSIS_RTOS_V2);

  • include文件放置若干头文件,这里我们关心list.h就可以了。其他头文件说明将在之后进行更新。
  • portable文件夹包括GCC和MemMang文件夹;GCC下包括port.c和portmacro.h两个文件。MemMang包括heap_4.c,这是内存分配方案4,FreeRTOS总共提供5中内存分配方案,文件分别为heap_x.c,x=1,2,3,4,5,一般默认x=4。之后会更新这些文件的说明。

(2):croutine.c、event_groups.c、list.c、queue.c、stream_buffer.c、task.c、timers.c.这里只需要关心list.c就可以了,其他头文件说明将在之后进行更新。

基本概念:

  • freertos中变量名以c、s、l、p、u、x开头,分别代表该变量为char,short/16位,long/32位,pointer(指针)、unsigned和其他类型。
  • freertos中Tab键等于4个空格,不是8个,因此编程时不推荐使用Tab键。

什么是list和list_item?

list:实际上是C语言中的链表,而list_item即C语言中链表的节点。

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现。链表的节点包括数据项和指针项;其中数据项用来存储数据,指针项指向下一个/上一个节点的物理地址!链表的节点/结点实际上是一种特殊的结构体。ps:(链表的【头节点/头结点】只存在指针项不存在数据项,指针项用来指出链表物理存储区域的开始地址,链表可以不需要【头节点/头结点】)。在list.h中定义FreeRTOS使用的xLIST_ITEM、xMINI_LIST_ITEM、xLIST三种结构体。首元节点:链表种第一个含有数据项的节点。

C语言list头文件_freertos中的list.c和list.h文件详解_第3张图片

(1)首先分析configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES==0时,即忽略用于检查链表数据的完整性的相关参数。

list.h初探

list.h定义了3种链表节点,分别是普通节点xLIST_ITEM、精简节点xMINI_LIST_ITEM、头节点xLIST。因为头节点和普通节点的数据结构和含义并不完全相同,因此尽管头节点xLIST包含数据项,我在这里任然称其为头节点,而不是首元节点。三种结构的定义依次如下:

struct 
  1. 首先定义了结构体xLIST_ITEM/ListItem_t,两个名字都代表同一个结构体;
  2. configLIST_VOLATILE 是修饰符,视为VOLATILE修饰符即可;
  3. TickType_t 是类型uint32_t或uint16_t,由portmacro.h中的configUSE_16_BIT_TICKS定义;参数xItemValue,用来做排序,一般降序;后面的lists.c文件中的函数void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )会用到。
  4. pxNext和pxPrevious为xLIST_ITEM指针变量,分别指向下一个xLIST_ITEM节点和上一个xLIST_ITEM节点;
  5. pvOwner指针变量,指向拥有该节点的内核对象,一般是TCB;(不是很好理解,之后会完善)
  6. pvContainer指针变量,指向节点所在的列表
  7. void* 表示的是任意类型的指针;
  8. listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE/listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE两个变量用于检查链表数据的完整性,当configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES==1是需要自己设置为已知值。
struct 
  1. 首先定义了结构体xMINI_LIST_ITEM/MiniListItem_t,两个名字都代表同一个结构体;
  2. TickType_t 是类型uint32_t或uint16_t,由portmacro.h中的configUSE_16_BIT_TICKS定义;参数xItemValue用来做排序,一般降序;
  3. pxNext和pxPrevious为xLIST_ITEM指针变量,分别指向下一个xLIST_ITEM节点和上一个xLIST_ITEM节点;
  4. listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE用于检查链表数据的完整性,当configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES==1是需要自己设置为已知值。
  5. xMINI_LIST_ITEM比xLIST_ITEM少2个用于指向节点所属链表和所属内核对象的指针参数,也没有listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE。
typedef 
  1. 首先定义了结构体xLIST/List_t,两个名字都代表同一个结构体;
  2. configLIST_VOLATILE 是修饰符,视为VOLATILE修饰符即可;
  3. TickType_t 是类型uint32_t或uint16_t,由portmacro.h中的configUSE_16_BIT_TICKS定义;参数uxNumberOfItems链表节点计数器,用来表示该链表下有多少个链表节点的;
  4. pxIndex指针变量,用于遍历链表的所有节点,指向头节点内xListEnd的地址;
  5. xListEnd是一个MiniListItem_t节点,是链表的最后一个节点。因为FreeRTOS定义的链表是循环双向链表,因此XListEnd也是链表的第一节点。
  6. listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE/listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE两个变量用于检查链表数据的完整性,当configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES==1是需要自己设置为已知值。

list.c初探

其中list.c中定义了以下5个函数。

  • void vListInitialiseItem( ListItem_t * const pxItem )负责普通链表节点的初始化;
  • void vListInitialise( List_t * const pxList );负责头节点的初始化,即链表初始化;
  • void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )负责将pxNewListItem指向的普通节点插入pxList指向的链表的末尾,由于链表为循环链表,因此这里所说的末尾是把头节点去除之后的双链链表的末尾;
  • void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )负责在指定List插入list_item;
  • UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )负责删除链表中的普通链表节点;

1.0普通链表节点的初始化 void vListInitialiseItem( ListItem_t * const pxItem )

void 

链表节点(将list_item翻译为“列表项”,我认为不合适。链表和列表的数据结构是不同的)初始化。

pxItem

上句将节点所属的链表指向为空,此时链表节点不属于任何链表。此链表节点包括5个参数项!!使用的是ListItem_t 不是xMINI_ListItem_t 。

2.0链表头节点(最后一个节点)的初始化void vListInitialise( List_t * const pxList );链表头节点初始化完成后,链表已经存在,只是链表的节点数量只有头节点内的xListEnd节点,没有其他节点,因此节点数量等于0。头节点初始化即是链表初始化。

void 

uxNumberOfItems记录本链表种普通节点(ListItem_t节点)的总数量;

  • pxIndex指针向量指向头节点内部的精简版节点xListEnd的物理地址,用来遍历整个链表。
  • 精简版节点xListEnd的xItemValue等于portMAX_DELAY(0xffffffffUL或0xffffUL,取决于configUSE_16_BIT_TICKSd的值);表示xListEnd节点为链表的最后一个节点;
pxList
  • 以上两句分别分别将xListEnd节点的上一个节点和下一个节点指向自己,表示该链表除此xListEnd节点外,没有其他节点。
pxList
  • 上句设置链表的节点数量uxNumberOfItems初始化为0;/*UBaseType_t 类型是usigned long*/

3.0链表新增普通链表节点。void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )

void 

C语言list头文件_freertos中的list.c和list.h文件详解_第4张图片

PS:图中1号节点为链表的首元节点。

pxIndex = pxList->pxIndex; 链表的头节点的xLIST_ITEM节点地址,图中0号节点。

pxNewListItem->pxNext = pxIndex; 新增链表节点的下一个节点是头节点内的xLIST_ITEM节点。即图中的0号节点。

pxNewListItem->pxPrevious = pxIndex->pxPrevious;新增链表节点的上一个节点是原来头节点内的xLIST_ITEM节点的上一个节点,即节点4.

pxIndex->pxPrevious->pxNext = pxNewListItem;原来的头节点内的xLIST_ITEM节点的上一个节点(图中节点4)的下一个节点应该为新增加的链表节点5。

pxIndex->pxPrevious = pxNewListItem; 头节点内的xLIST_ITEM节点的上一个节点是新增链表节点5。

PS:头节点内xLIST_ITEM节点的上一个节点为除xLIST_ITEM节点外的最后一个节点,即图中节点4(pxIndex->pxPrevious);头节点的xLIST_ITEM节点的下一个节点为除xLIST_ITEM节点外的第一节点(pxIndex->pxNext),即图中节点1。

pxNewListItem->pvContainer = ( void * ) pxList;

新增的普通链表节点属于pxList指向的链表;

( pxList->uxNumberOfItems )++;

上句设置头节点的链表计数器uxNumberOfItems加1

4.0链表删除普通链表节点。UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )负责删除链表中的普通链表节点;

UBaseType_t 

这个返回有返回值,返回的是删除节点后,链表的数量。UBaseType_t 类型是usigned long

List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;找到要删除普通链表节点pxItemToRemove所属的 节点的;并将地址存储在指针变量pxList上。

pxItemToRemove

将要删除的链表节点的下一个节点(图中3号节点)的上一个节点指向要删除的节点的上一个节点(图中1号节点);

将要删除的链表节点的上一个节点(图中1号节点)的下一个节点指向要删除节点的下一个节点(图中3号节点)。

C语言list头文件_freertos中的list.c和list.h文件详解_第5张图片

PS:图中1号节点为链表的首元节点。

if( pxList->pxIndex == pxItemToRemove )
	{
		pxList->pxIndex = pxItemToRemove->pxPrevious;
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}

xList->pxIndex == pxItemToRemove,如果要删除的节点是头节点内的xListEnd,即链表的最后一个节点。则将除头节点内的xListEnd节点外的最后一个节点作为头节点的xListEnd。

	pxItemToRemove->pvContainer = NULL; 
	( pxList->uxNumberOfItems )--; 
	return pxList->uxNumberOfItems;

将删除的链表做初始化处理,即不属于任何链表;链表的计数器uxNumberOfItems减1;返回链表删除后的普通链表节点的数量uxNumberOfItems。

5.0将普通节点按照升序排序增加到链表中void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )

负责将pxNewListItem指向的普通节点插入pxList指向的首元节点(链表)的末尾;

void 

TickType_t xValueOfInsertion = pxNewListItem->xItemValue;首先是获取待插入的链表节点的赋值值xItemValue;TickType_t 是类型uint32_t或uint16_t,由portmacro.h中的configUSE_16_BIT_TICKS定义;首先判定该值是否为最大值portMAX_DELAY。如果是,直接将待插入的普通链表节点插入到链表的末尾即可。否则进入for循环,找到待插入的位置。比如现在有5个节点,他们的xItemValue分别是11,13,15,17,19。如果待插入的链表节点的xItemValue=XX,XX大于等于19或等于portMAX_DELAY。则插入后的顺序为头节点,11,13,15,17,19,XX。

for

假设XX=13则for循环以后pxIterator等于xItemValue=13对应节点的物理地址。

假设XX=14则for循环以后pxIterator等于xItemValue=15对应节点的物理地址。

假设XX=15则for循环以后pxIterator等于xItemValue=15对应节点的物理地址。

以XX=15为例:

	pxNewListItem->pxNext = pxIterator->pxNext; 
	pxNewListItem->pxNext->pxPrevious = pxNewListItem; 
	pxNewListItem->pxPrevious = pxIterator; 
	pxIterator->pxNext = pxNewListItem;
  • 待插入的链表节点的下一个节点指向pxIterator的下一个节点(即17号节点);
  • 待插入的链表节点的下一个节点(17号)的上一个节点指向指向带插入节点;
  • 待插入的链表节点的上一个节点指向之前的old15号节点;(也就是xItemValue相同的情况下,待加入的节点加载原先的节点的后面,比如原来已经有10个xItemValue=15的,则待加入的链表节点应该在添加在之前10个链表节点的后面);
  • 待插入节点的上一个节点是pxIterator(old之前的15号)的下一个节点指向带插入节点(15号);
  • PS:图中11号节点为链表的首元节点。

C语言list头文件_freertos中的list.c和list.h文件详解_第6张图片

list.h文件还定义了若干的带宏参数:

#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )		( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
#define listGET_LIST_ITEM_OWNER( pxListItem )	( ( pxListItem )->pvOwner )

初始化/获取链表节点的内核对象拥有者

#define listSET_LIST_ITEM_VALUE( pxListItem, xValue )	( ( pxListItem )->xItemValue = ( xValue ) )
#define listGET_LIST_ITEM_VALUE( pxListItem )	( ( pxListItem )->xItemValue )

初始化/获取链表节点的排序辅助值

#define listGET_HEAD_ENTRY( pxList )	( ( ( pxList )->xListEnd ).pxNext )
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )	( ( ( pxList )->xListEnd ).pxNext->xItemValue )

获取头节点内xListEnd节点的下一个链表节点地址的,即实际的链表的首元节点地址

获取首元节点的xItemValue值。

#define listGET_NEXT( pxListItem )	( ( pxListItem )->pxNext )

获取链表节点的下一个节点的地址

#define listGET_END_MARKER( pxList )	( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )

获取链表的头节点内xListEnd的地址,即最后一个节点的物理地址。

#define listLIST_IS_EMPTY( pxList )	( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) )
#define listCURRENT_LIST_LENGTH( pxList )	( ( pxList )->uxNumberOfItems )

判断链表是否为空及链表拥有普通链表节点的数量uxNumberOfItems,uxNumberOfItems=0时为链表为空链表。

#define listGET_OWNER_OF_HEAD_ENTRY( pxList )  ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner )

获取链表首元节点的内核对象拥有者

#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pvContainer )

获取链表节点所属的链表

#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( BaseType_t ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) ) )

判断链表节点是否被指定的链表所包含

#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )

判断链表是否完成初始化

void 

这一段没看懂,求大神赐教

#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )										
{																							
List_t * const pxConstList = ( pxList );													
	/* Increment the index to the next item and return the item, ensuring */				
	/* we don't return the marker used at the end of the list.  */							
	( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;							
	if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )	
	{																						
		( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;						
	}																						
	( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;											
}

获取首元节点所属的内核对象拥有者


#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )

	/* Define the macros to do nothing. */
	#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
	#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
	#define listFIRST_LIST_INTEGRITY_CHECK_VALUE
	#define listSECOND_LIST_INTEGRITY_CHECK_VALUE
	#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
	#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
	#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )
	#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )
	#define listTEST_LIST_ITEM_INTEGRITY( pxItem )
	#define listTEST_LIST_INTEGRITY( pxList )
#else
	/* Define macros that add new members into the list structures. */
	#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE				TickType_t xListItemIntegrityValue1;
	#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE				TickType_t xListItemIntegrityValue2;
	#define listFIRST_LIST_INTEGRITY_CHECK_VALUE					TickType_t xListIntegrityValue1;
	#define listSECOND_LIST_INTEGRITY_CHECK_VALUE					TickType_t xListIntegrityValue2;

	/* Define macros that set the new structure members to known values. */
	#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )		( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
	#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )	( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
	#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )		( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
	#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )		( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE

	/* Define macros that will assert if one of the structure members does not
	contain its expected value. */
	#define listTEST_LIST_ITEM_INTEGRITY( pxItem )		configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
	#define listTEST_LIST_INTEGRITY( pxList )			configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
#endif /* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES */

以上代码用于检查链表节点数据的完整性,目前还没有接触到。等研究明白了更新。或者指导的大神,请不吝赐教。谢谢

c语言知识链表参考:https://blog.csdn.net/baidu_41813368/article/details/82776527

你可能感兴趣的:(C语言list头文件)