在 LIST_FOREACH() 宏中添加 _node 变量只是为了代码的可读性吗?

Is _node variable in LIST_FOREACH() macro added only for code readability?

在一个宏中,我注意到有一个变量 _node 似乎是多余的,因为它可以被删除并完全替换为 V.

它唯一一次单独使用是在 for 循环中的测试表达式中。

_node甚至有一个下划线前缀,这意味着它是一个仅供内部使用的变量。

_node 出现在这个宏中是为了让人们更容易阅读吗?

#define LIST_FOREACH(L, S, M, V)\
ListNode *_node = NULL;\
ListNode *V = NULL;\
for(V = _node = L->S; _node != NULL; V = _node = _node->M)

用法示例

void List_destroy(List * list)
{
    LIST_FOREACH(list, first, next, cur) { 
        if (cur->prev){
            free(cur->prev);
        }
    }
    free(list->last);
    free(list);
}

已创建 Typedef

typedef struct ListNode {
    struct ListNode *next;
    struct ListNode *prev;
    void *value; 
} ListNode;

typedef struct List { 
    int count; 
    ListNode *first;
    ListNode *last;
} List;

认为 _node 变量的要点是使循环主体可以自由修改 V 而不会影响迭代。我不会这样写的;我会改用

#define LIST_FOREACH(L, S, M, V) \
    for(ListNode *V = (L)->S; V; V = V->M)

因为我认为不要用变量声明污染外部作用域,并允许 LIST_FOREACH 嵌套,这些更为重要。但是我可以看到单独的 V_node.

的论点

宏使代码不可读。这是一种非常糟糕的编程风格。

如果要替换此函数中的宏

void List_destroy(List * list)
{
    LIST_FOREACH(list, first, next, cur) { 
        if (cur->prev){
            free(cur->prev);
        }
    }
    free(list->last);
    free(list);
}

对于它的扩展,你将得到

void List_destroy(List * list)
{
    ListNode *_node = NULL;
    ListNode *cur = NULL
    
    for( cur = _node = list->first; _node != NULL; cur = _node = _node->next )
    {
        if (cur->prev){
            free(cur->prev);
        }
    }
    free(list->last);
    free(list);
}

立即可以看出变量cur_node应该在使用它们的for循环中声明。此外,变量 _node 只是多余的。

函数可以改写成下面的方式

void List_destroy(List * list)
{
    for( ListNode *cur = list->first; cur != NULL; cur = cur->next )
    {
        free( cur->prev );
    }
    
    free( list->last );
    free( list );
}

但是这样定义函数更简单正确

void List_destroy( List *list )
{
    while ( list->first != NULL )
    {
        ListNode *tmp = list->first;
        list->first = lits->first->next;
        free(  tmp );
    }

    list->last = NULL;    
    list->count = 0;
}

该函数不应释放指向的列表本身。例如,用户可以定义列表

List list = { .count = 0, .first = NULL, .last = NULL };

也就是说,struct List 类型的对象不必动态分配。

另外,完全不清楚数据成员value是否指向一个动态分配的对象,以及为什么它没有被释放。

所以一般来说函数应该是这样的

void List_destroy( List *list )
{
    while ( list->first != NULL )
    {
        ListNode *tmp = list->first;
        list->first = lits->first->next;
        free( tmp->value );
        free(  tmp );
    }

    list->last = NULL;    
    list->count = 0;
}

所以在我看来,您在某个地方发现了一段非常糟糕的代码,不值得讨论。:)