我们的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)
块,也没有运气。我正在尝试甚至可能吗?谢谢!
答案 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
感到高兴:)