Как `({...})` возвращает значение? - PullRequest
11 голосов
/ 20 октября 2011

Недавно я нашел этот макрос GCC:

#define max(a,b) \
   ({ typeof (a) _a = (a); \
       typeof (b) _b = (b); \
     _a > _b ? _a : _b; })

До того, как увидел этот код, я не осознавал, что блок кода {...} может каким-то образом возвращать значение в C.
1) Не могли бы вы дать мне подсказку, как это работает?

Хотя мне обычно удавалось добиться того же результата, используя оператор запятой:

#define max(a,b) \
    (typeof (a) _a = (a), \
     typeof (b) _b = (b), \
     (_a > _b ? _a : _b)) 

или еслиэто было бы только для побочного эффекта, я бы использовал do { ... } while(0)

2) Каков предпочтительный способ сделать это?

Ответы [ 2 ]

10 голосов
/ 20 октября 2011

Это расширение GCC.Оператор запятой не работает:

// C89, doesn't work...
#define max(a,b) \
    (typeof (a) _a = (a), \
     typeof (b) _b = (b), \
     (_a > _b ? _a : _b)) 

Оператор запятой работает только с выражениями, а typeof(a) _a = (a); является объявлением, а не выражением.На самом деле невозможно написать эквивалентный макрос без расширений GCC или C11, который имеет _Generic.Обратите внимание, что typeof также является расширением GCC, поэтому вы не получите никакой переносимости, исключив ({...}), если не исключите также typeof.

Вот версия C11, обратите внимание, насколько она многословна.сравнение (и оно обрабатывает только два типа!).C11 даже еще не поддерживается, удачи, пытаясь найти компилятор для проверки этого:

// C11
static inline int maxi(int x, int y) { return x > y ? x : y; }
static inline long maxl(long x, long y) { return x > y ? x : y; }
#define max(x, y) _Generic((x), \
    long: maxl(x,y), \
    int:_Generic((y), \
        int: maxi(x,y), \
        long: maxl(x,y)))

В переносимом C99 вы можете написать макрос или встроенную функцию, которая достигает того же эффекта, за исключением он будет работать только для одного типа на макрос.

// C99
static inline int maxi(int x, int y) { return x > y ? x : y; }

В C89 / C90 я не могу придумать, как написать макрос так, чтобы он не оценивался x или y дважды.

9 голосов
/ 20 октября 2011

Конструкция ({ ... }) является расширением gcc.

Как и оператор typeof.

A MAX макрос(обратите внимание на обычное использование всех заглавных букв) достаточно просто написать:

#define MAX(a, b) ((a) > (b) ? (a) : (b))

Он оценивает один из своих аргументов более одного раза, поэтому вы не должны вызывать его как, например, MAX(x++, y--).Использование всех заглавных букв служит для того, чтобы напомнить пользователю, что это макрос, а не функция, и быть осторожным с аргументами с побочными эффектами.

Или вы можете написать функцию (возможно, встроенную) для каждоготип.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...