In mehreren ARM-Back-Ends von Linux sehe ich Dateien clkdev.h
diese Makrodefinition:
#define __clk_get(clk) ({ 1; })
Siehe zum Beispiel ./arch/arm/mach-versatile/include/mach/clkdev.h
Dieses Makro verwendet die GCC-Erweiterung Anweisungen und Deklarationen in Ausdrücken
Später wird dieses Makro in Datei verwendet ./drivers/clk/clkdev.cin Funktion clk_get_sys()
if (cl && !__clk_get(cl->clk))
cl = NULL;
Ich frage mich, warum hier nicht ein einfaches Makro verwendet wird:
#define __clk_get(clk) (1)
BEARBEITEN:
Ich habe eine andere Verwendung dieses Konstrukts in den Kernelquellen gefunden, die das folgende grep-Muster verwendet:
grep -R '({[[:space:]]*[a-zA-Z0-9_()+=/!&*>., ?:-]\+[[:space:]]*;[[:space:]]*})' .
Hier sind einige der Spiele:
./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
./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;})
[...]
Hinweis: Das Konstrukt ({if(put_user(d, (typeof (d)*)a)) return -EFAULT;})
scheint eine gute Verwendung der zusammengesetzten Anweisung zu sein. Dies kann aber auch durch typischere ersetzt werden do { if(put_user(d, (typeof (d)*)a)) return -EFAULT; } while(0)
Ein Streichholz kam zurück grep
ist interessant: ein ./include/asm-generic/bug.h Es gibt einen Kommentar zur Verwendung von ({ 0; })
. Das ist ganz die gleiche Antwort von AndreyT.
In der Tat kann man nicht verwenden ((void)0)
da es nicht als r-Wert verwendet werden kann.
({ 0; })
funktioniert jeweils.
Wenn Sie also ein Makro haben, das wie eine Funktion verwendet werden kann, die einen Wert zurückgibt, der verwendet werden kann oder nicht, scheint die zusammengesetzte Anweisung Ihre einzige Option zu sein.
Aber __clkget()
wird nie als etwas anderes als r-Wert verwendet
Einige Verknüpfungen
- http://www.toofishes.net/blog/gcc-compound-statement-expressions/
- Abstruses #define-Makro in Linux-Kernel-Quelle gefunden
- Makro: Bedeutet #define a(b) ({… c;}) dass a(b) c zurückgibt?
- Warum brauchen wir Klammern um das Blockmakro?
- Sind zusammengesetzte Anweisungen (Blöcke) in ANSI C von Klammerausdrücken umgeben?
Ich vermute, dass das Makro früher etwas Fleisch hatte, und irgendwann hat es jemand gehackt, um es immer auf 1 auszuwerten, ohne die Klammer-Klammer-Syntax der GCC-Erweiterung zu entfernen.
– Telefontagger
18. Dezember 2012 um 17:44 Uhr
Nein, jetzt denke ich, dass die Klammer-Klammern-Syntax der GCC-Erweiterung möglicherweise eine Warnung “Bedingter Ausdruck immer wahr” zunichte macht?
– Telefontagger
18. Dezember 2012 um 17:49 Uhr
@phonetagger Ist das eine gcc-Warnung? Aber ich sehe, dass eine MSVC C4127-Warnung möglich ist.
– Joseph Quinsey
18. Dezember 2012 um 19:14 Uhr
@JosephQuinsey – Ich bekomme selbst keine solche Warnung, aber ein Typ, der mit mir zusammenarbeitet, nimmt ständig Änderungen am Code vor, die alle anderen einchecken, weil seine Version von GCC auf seiner eigenen Linux-Box viel neuer ist als die Version, die alle anderen verwenden server, und die normalen Codierungspraktiken aller anderen funktionieren anscheinend nicht so gut (in Bezug auf Warnungen), egal welche Version er verwendet. Ich weiß nicht, welche Version er verwendet.
– Telefontagger
18. Dezember 2012 um 19:55 Uhr
@H2CO3 Ich glaube nicht, dass jemand den Vanilla-Linux-Kernel mit Microsoft-Produkten kompilieren kann.
– Alvin Wong
19. Dezember 2012 um 12:16 Uhr