Yan*_*aud 27 c linux macros gcc linux-kernel
在Linux的多个ARM后端,我在文件中看到clkdev.h这个宏定义:
#define __clk_get(clk) ({ 1; })
Run Code Online (Sandbox Code Playgroud)
参见例如 ./arch/arm/mach-versatile/include/mach/clkdev.h
后来这个宏在文件./drivers/clk/clkdev.c中用于函数clk_get_sys()
if (cl && !__clk_get(cl->clk))
cl = NULL;
Run Code Online (Sandbox Code Playgroud)
我想知道为什么不在这里使用一个简单的宏:
#define __clk_get(clk) (1)
Run Code Online (Sandbox Code Playgroud)
编辑:
我使用以下grep模式在整个内核源代码中找到了此构造的一些其他用法:
grep -R '({[[:space:]]*[a-zA-Z0-9_()+=/!&*>., ?:-]\+[[:space:]]*;[[:space:]]*})' .
Run Code Online (Sandbox Code Playgroud)
这是一些比赛:
./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;})
[...]
Run Code Online (Sandbox Code Playgroud)
注意:该构造({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值那样被用作其他东西
我注意到在-Wall模式下,独立(1);表达式语句生成"无效语句"警告,而独立({ 1; });表达式语句不生成警告.
也许在代码中的某处,它们最终会出现__clk_get忽略结果的独立调用.该(1)定义将导致对此类调用的警告,同时({ 1; })保持安静,同时在其他上下文中产生相同的效果.
为什么这个宏被定义为({1;})?
这一切都取决于程序员的编码风格.它只是返回值1.例如,x86在" include/asm-generic/clkdev.h"中的arch ,__clk_get定义为
static inline int __clk_get(struct clk *clk) { return 1; }
Run Code Online (Sandbox Code Playgroud)
也在linux/arch/c6x/include/asm/clkdev.h中
static inline int __clk_get(struct clk *clk)
{
return 1;
}
Run Code Online (Sandbox Code Playgroud)