直接上原始碼分析
void vListInitialise( List_t * const pxList )
{
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /* 此時連結串列中只有一個列表項(結點) */
pxList->xListEnd.xItemValue = portMAX_DELAY; /* 輔助值,用來做升序 */
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd )
pxList->uxNumberOfItems = ( UBaseType_t ) 0U; /* 記錄列表中節點的數量 */
}
void vListInitialiseItem( ListItem_t * const pxItem )
{
/* 標記此節點屬於哪個列表。初始化為NULL */
pxItem->pxContainer = NULL;
}
void vListInsertEnd( List_t * const pxList,
ListItem_t * const pxNewListItem )
{
ListItem_t * const pxIndex = pxList->pxIndex; /* 先拿到這個連結串列的索引,網上說這個索引指向列表項的頭部,但是初始化並沒有這個操作 */
pxNewListItem->pxNext = pxIndex; /* 新插入的節點的下一個節點就是這個pxIndex節點 ,新插入的節點指向了末尾節點 */
pxNewListItem->pxPrevious = pxIndex->pxPrevious; /* pxIndex->pxPrevious 指向的是列表的末尾節點,pxNewListItem->pxPrevious 新插入的節點的上一個等於末尾的節點,不知道為什麼要這樣 */
pxIndex->pxPrevious->pxNext = pxNewListItem; /* pxIndex->pxPrevious->pxNext本來是指向自己,現在指向的是新節點,等於連線起來 */
pxIndex->pxPrevious = pxNewListItem; /* 基本操作了,連結節點 */
pxNewListItem->pxContainer = pxList; /* 標記狀態 */
( pxList->uxNumberOfItems )++; /* 節點加1,這裡為什麼加括號? */
}
void vListInsert( List_t * const pxList,
ListItem_t * const pxNewListItem )
{
ListItem_t * pxIterator; /* 新建的節點 , 輔助值 */
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; /* 就用這個新的節點值來排序 */
if( xValueOfInsertion == portMAX_DELAY )
{
pxIterator = pxList->xListEnd.pxPrevious; /* 如果要插入的節點的值等於最大值,那就插在End的前一個節點的位置 */
}
else
{
/* 首先pxIterator指向此連結串列的最後一個節點,判斷新插入的節點的值和pxIterator下一個節點的值
此時 pxIterator->pxNext->xItemValue就是首節點的值,(為什麼是首節點,因為初始化pxIterator指向了End節點,pxIterator = ( ListItem_t * ) &( pxList->xListEnd ))
如果插入的值大於pxIterator->pxNext->xItemValue(第一次是首節點的值),那麼pxIterator=pxIterator->pxNext ,即指向下一個節點繼續迴圈
如果插入的值小於pxIterator->pxNext->xItemValue,那麼就說明找到了要插入的地方
那就是新插入的到pxIterator的後面,要插入的節點就是pxIterato和 pxIterato->next之間。
*/
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) { }
}
pxNewListItem->pxNext = pxIterator->pxNext; /* 首先把 pxIterator->pxNext 賦值給 pxNewListItem->pxNext,讓新列表項指向原本列表中下一個列表項 */
pxNewListItem->pxNext->pxPrevious = pxNewListItem; /* 把 pxNewListItem->pxNext(也就是原本列表中下一個列表項)的 pxNewListItem->pxNext->pxPrevious 成員指向待插入列表項 pxNewListItem,實現雙向連結串列 */
pxNewListItem->pxPrevious = pxIterator; /* 新插入的上一個指向pxIterator,就是上面說的,新的節點插到pxIterator的後面 */
pxIterator->pxNext = pxNewListItem; /* pxIterator->pxNext : 原來的pxIterator節點 (此時只是插入節點,xIterator->pxNext一定要指向pxNewListItem,實現節點的連結)的下一個就是新的節點了 */
pxNewListItem->pxContainer = pxList; /* 老套路了 */
( pxList->uxNumberOfItems )++; /* 列表項個數加1 */
}
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
List_t * const pxList = pxItemToRemove->pxContainer; /* 得到要刪除節點連結串列 */
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious; /* 這裡就只是改變指標前後連結 */
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
mtCOVERAGE_TEST_DELAY(); /* 這裡為什麼要存在空函式? */
if( pxList->pxIndex == pxItemToRemove ) /* 很好理解,不做解釋 */
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
pxItemToRemove->pxContainer = NULL; /* 已經都刪除節點了,這個節點的屬主連結串列肯定不存在啊 */
( pxList->uxNumberOfItems )--; /* 老套路了 */
return pxList->uxNumberOfItems; /* 返回這個連結串列還有幾個節點 */
}
// 仍有疑問,希望有人看到能解答一下,在下感激不盡。