又一个宏技巧

(本文为《C语言编程艺术》的一部分。)

这个技巧是从 Nick Bowler 的一封邮件中看来的,非常有意思,分享一下。

情况是这样的:在 Linux 内核中,有一个函数 kmap_atomic(),它之前带两个参数,而现在,它的第二个参数已经名存实亡了,可以直接去掉。所以问题就出来了,如何警告使用 kmap_atomic() 的人带有两个参数的形式是过时的?换句话说,怎么才能在用两个参数调用 kmap_atomic() 时发出警告而用一个参数调用时就没有警告?

所以下面的技巧就出来了。

[c]

define PASTE(a, b) a ## b

define PASTE2(a, b) PASTE(a, b)

define NARG_(_2, _1, n, …) n

define NARG(…) NARG(_VA_ARGS, 2, 1, :)

static inline void kmap_atomic(struct page page)
{
return __kmap_atomic(page);
}

static inline void __deprecated kmap_atomic_deprecated(struct page page,
enum km_type km)
{
return kmap_atomic(page);
}

define kmapatomic1(…) kmapatomic(__VA_ARGS)

define kmapatomic2(…) kmapatomic_deprecated(__VA_ARGS)

define kmapatomic(…) PASTE2(kmapatomic, NARG(VA_ARGS)(__VA_ARGS))

[/c]

这里最精妙的地方当属 NARGS 这个宏的定义,它通过参数个数来决定返回值,进而通过 PASTE2 来选择是 kmap_atomic1,还是 kmap_atomic2,而后者是过期的。如果用户用了两个参数,他就会得到类似下面的编译警告:

drivers/block/drbd/drbd_bitmap.c:973:3: warning: ‘kmap_atomic_deprecated’ is deprecated (declared at /home/wangcong/linux-2.6/include/linux/highmem.h:124)

非常聪明,不是吗? :)