我们的C代码库乱扔了类似图案的代码,这些代码在具有相同类型的.next
指针的结构上执行相同的迭代,NULL
处理等。作为自己:
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)
块,也没有运气。我正在尝试什么?谢谢!
我稍微改变了宏的内部行为。它不仅可以工作,而且更适合代码库:
#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块返回值,值必须仅将放置在简单的,结肠端终止的表达式中(完整说明(,否则该块将返回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
Happy:(