Являются ли составные утверждения (блоки) окруженными выражениями parens в ANSI C?

Просматривая источники ядра Linux, я нашел часть кода, где блок операторов, окруженных скобками, рассматривается как выражение a la lisp (или ML), то есть выражение, значение которого является значением последнего оператора.

Например:

int a = ({
    int i;
    int t = 1;
    for (i = 2; i<5; i++) {
        t*=i;
    }
    t;
});

Я рассматривал грамматику ANSI C

Ответ 1

Он называется "braced-group in expression".

Это не разрешено ANSI/ISO C или С++, но gcc поддерживает его.

Ответ 2

Это не действует C это gcc расширение называется выражение выражения, вы можете найти полный список расширений C здесь. Это на самом деле одно из многих расширений gcc, используемых в ядре Linux, и похоже, что clang тоже поддерживает это, и хотя он явно не указан в документе.

Как вы заметили, последнее выражение служит значением выражения, в документе говорится (внимание мое):

Последнее в составном выражении должно быть выражением, за которым следует точка с запятой; значение этого подвыражения служит значением всей конструкции. (Если вы используете какой-то другой оператор, последний в фигурных скобках, конструкция имеет тип void и, следовательно, фактически не имеет значения.)

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

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

который дважды оценивает a или b и может быть переписан для устранения этой проблемы с использованием выражений оператора следующим образом:

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

Обратите внимание, что необходимо явно использовать int который может быть установлен с использованием другого расширения gcc Typeof:

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

Обратите внимание, что clang также поддерживает typeof.