附加简单链表的通用C宏

时间:2018-02-16 13:21:33

标签: c macros

我们的C代码库中充斥着类似模式的代码,它对具有相同类型的NULL指针的结构上的任何“list append”操作执行相同的迭代,.next处理等。他们自己:

struct foo {
    int bar;
    char *baz;
    struct foo *next;
}

示例模式代码:

struct foo *foo_list;

int func(struct foo *f) {
    struct foo *it;

    ...

    if (!foo_list) {
        foo_list = f;
    } else {
        for (it = foo_list; it->next; it = it->next)
            {}
        it->next = f;
    }

     ...
}

我正在尝试提出一个宏来简化任何具有此类.next成员的结构的追加过程。请记住,也可以对NULL列表进行添加,因此宏也必须返回新的列表头:

#define add_last(what, where) \
    ({ \
        if (!(where)) { \
            (what); \
        } else { \
            typeof(where) __wit = (where); \
            while (__wit->next) \
                __wit = __wit->next; \
            __wit->next = (what); \
            (where); \
        }})

然而,当像这样使用它时:

return add_last(filter, filters);

gcc不太高兴,并且喷出:

cachedb/../db/../ut.h:104:4: warning: statement with no effect [-Wunused-value] (what); \ ^ cachedb/cachedb.c:797:9: note: in expansion of macro ‘add_last’ return add_last(new, existing); ^ cachedb/../db/../ut.h:110:4: warning: statement with no effect [-Wunused-value] (where); \ ^ cachedb/cachedb.c:797:9: note: in expansion of macro ‘add_last’ return add_last(new, existing); ^ cachedb/../db/../ut.h:103:2: error: void value not ignored as it ought to be ({ if (!(where)) { \ ^ cachedb/cachedb.c:797:9: note: in expansion of macro ‘add_last’ return add_last(new, existing); ^

我尝试了do while (0)块,也没有运气。我正在尝试甚至可能吗?谢谢!

1 个答案:

答案 0 :(得分:3)

我略微改变了宏的内部行为。它不仅现在有效,而且更符合代码库:

#define add_last(what, where) \
    do { \
        if (!(where)) { \
            (where) = (what); \
        } else { \
            typeof(where) __wit = (where); \
            while (__wit->next) \
                __wit = __wit->next; \
            __wit->next = (what); \
        } \
    } while (0)

所以不要像下面那样使用它,它在大多数情况下执行无关的写操作:

filters = add_last(filter, filters);

,您现在只需使用它:

add_last(filter, filters);

原始return代码变为:

add_last(filter, filters);
return filters;

尽管如此,关于原始解决方案为什么会抛出这些警告的任何提示都会有所帮助。那些不是“没有效果的陈述”恕我直言 - 它们作为块返回值很有用。

最终答案:为了让C块返回一个值,值必须只放在一个简单的冒号终止表达式中{{3} }),否则该块将返回void。所以我们原来的宏观想法(我将不再使用它)只有在调整如下时才有效:

#define add_last(what, where) \
    do { \
        typeof(where) __wit; \
        if (!(where)) { \
            __wit = (what); \
        } else { \
            __wit = (where); \
            while (__wit->next) \
                __wit = __wit->next; \
            __wit->next = (what); \
            __wit = (where); \
        } \
        __wit; \
    } while (0)

这最终会让gcc感到高兴:)