27

在 Linux 的多个 ARM 后端中,我在文件中看到了clkdev.h这个宏定义:

#define __clk_get(clk) ({ 1; })

参见例如 ./arch/arm/mach-versatile/include/mach/clkdev.h

此宏在表达式中使用 GCC 扩展语句和声明

后来这个宏在文件./drivers/clk/clkdev.c中使用,在函数中clk_get_sys()

 if (cl && !__clk_get(cl->clk))
         cl = NULL;

我想知道为什么不在这里使用一个简单的宏:

#define __clk_get(clk) (1)

编辑:

我使用以下 grep 模式在整个内核源代码中发现了此构造的其他一些用法:

grep -R '({[[:space:]]*[a-zA-Z0-9_()+=/!&*>., ?:-]\+[[:space:]]*;[[:space:]]*})' .

以下是部分比赛:

./kernel/trace/trace_selftest.c:# define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; })
./kernel/profile.c:#define create_hash_tables()         ({ 0; })
./include/asm-generic/bug.h: * Use of ({0;}) because WARN_ON_SMP(x) may be used either as
./include/asm-generic/bug.h:# define WARN_ON_SMP(x)         ({0;})
./include/linux/key.h:#define key_get(k)            ({ NULL; })
./include/linux/key.h:#define key_get(k)            ({ NULL; })
./include/linux/audit.h:#define audit_alloc(t) ({ 0; })
./include/linux/audit.h:#define audit_bprm(p) ({ 0; })
./include/linux/audit.h:#define audit_sockaddr(len, addr) ({ 0; })
./include/linux/audit.h:#define audit_log_bprm_fcaps(b, ncr, ocr) ({ 0; })
./include/linux/audit.h:#define audit_log_start(c,g,t) ({ NULL; })
./include/linux/atalk.h:#define atalk_proc_init()   ({ 0; })
./include/linux/ftrace.h:#define register_ftrace_function(ops) ({ 0; })
./include/linux/ftrace.h:#define unregister_ftrace_function(ops) ({ 0; })
./include/linux/ftrace.h:#define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; })
./include/linux/ftrace.h:#define ftrace_set_filter(ops, buf, len, reset) ({ -ENODEV; })
./include/linux/ftrace.h:#define ftrace_set_notrace(ops, buf, len, reset) ({ -ENODEV; })
./include/linux/cpu.h:#define unregister_hotcpu_notifier(nb)    ({ (void)(nb); })
./include/linux/proc_fs.h:#define proc_net_fops_create(net, name, mode, fops)  ({ (void)(mode), NULL; })
./arch/powerpc/include/asm/pgtable-ppc64.h:#define pgd_set(pgdp, pudp)  ({pgd_val(*(pgdp)) = (unsigned long)(pudp);})
./arch/sh/math-emu/math.c:#define WRITE(d,a)    ({if(put_user(d, (typeof (d)*)a)) return -EFAULT;})
./arch/sh/math-emu/math.c:#define READ(d,a) ({if(get_user(d, (typeof (d)*)a)) return -EFAULT;})
[...]

注意:该构造({if(put_user(d, (typeof (d)*)a)) return -EFAULT;})似乎是复合语句的一个很好的用法。但这也可以换成更典型的do { if(put_user(d, (typeof (d)*)a)) return -EFAULT; } while(0)

返回的一个匹配项grep很有趣:在./include/asm-generic/bug.h中有一条使用({ 0; }). 这与AndreyT 答案完全相同。

确实,不能使用((void)0),因为它不能用作 r 值。 ({ 0; })在每种情况下都有效。

因此,如果您有一个可以像函数一样使用的宏,该函数返回一个可以使用或不可以使用的值,那么复合语句似乎是您唯一的选择。

但从__clkget()不用作其他任何东西作为 r 值

一些链接

4

3 回答 3

9

我注意到在-Wall模式下,独立(1);表达式语句会生成“无效的语句”警告,而独立({ 1; });表达式语句不会产生警告。

也许在代码的某个地方,他们以某种方式最终以__clk_get忽略结果的独立调用而告终。该(1)定义将导致对此类调用发出警告,同时({ 1; })在其他情况下产生相同效果时保持安静。

于 2012-12-19T07:31:47.863 回答
8

为什么这个宏被定义为 ({ 1; })?

这完全取决于程序员的编码风格。它所做的只是返回值 1。例如,在“ ”中的x86arch 上,定义为include/asm-generic/clkdev.h__clk_get

static inline int __clk_get(struct clk *clk) { return 1; }

也在 linux/arch/c6x/include/asm/clkdev.h

static inline int __clk_get(struct clk *clk)
{
        return 1;
}
于 2012-12-19T06:06:39.600 回答
0

一种可能的解释是防止在不良情况下使用。
这对于提高代码可移植性很有用——如果另一个架构的宏实现失败,我们希望这个也失败。

示例:static int x = __clk_get(clk);- 使用时钟进行静态初始化是没有意义的。
使用#define __clk_get(clk) (1),它将起作用。
#define __clk_get(clk) ({ 1; })它将失败。

于 2012-12-19T12:57:34.030 回答