Подтвердить что ты не робот

Почему этот макрос определяется как ({1;})?

В нескольких ARM-серверах Linux я вижу в файлах 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)

EDIT:

Я нашел другое использование этой конструкции в источниках ядра, используя следующий шаблон 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 там комментарий использования of ({ 0; }). Это то же самое ответ AndreyT.

Действительно, нельзя использовать ((void)0), так как он не будет использоваться в качестве r-значения. ({ 0; }) работает в каждом случае.

Итак, если у вас есть макрос, который может использоваться как функция, возвращающая значение, которое может быть использовано или нет, составной оператор кажется вашим единственным вариантом.

Но __clkget() никогда не используется как что-либо еще, как r-значение

Некоторые ссылки

4b9b3361

Ответ 1

Я замечаю, что в режиме -Wall автономный оператор выражения (1); генерирует предупреждение "выражение без эффекта", в то время как автономный оператор выражения ({ 1; }); не вызывает никаких предупреждений.

Возможно, где-то в коде они каким-то образом заканчиваются автономными вызовами __clk_get, которые игнорируют результат. Определение (1) приведет к предупреждению для таких вызовов, в то время как ({ 1; }) будет сохранять тишину при создании того же эффекта в других контекстах.

Ответ 2

Почему этот макрос определяется как ({1;})?

Все зависит от стиля программирования программиста. Все, что он делает, это вернуть значение 1. Например, в x86 arch в "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;
}

Ответ 3

Возможное объяснение - предотвратить использование в нежелательных ситуациях.
Это полезно для улучшения переносимости кода - если другая реализация макроса макроса завершится неудачно, мы также хотим, чтобы этот сбой тоже не работал.

Пример: static int x = __clk_get(clk); - нет смысла в статической инициализации с помощью часов.
С #define __clk_get(clk) (1) он будет работать.
С #define __clk_get(clk) ({ 1; }) он не работает.