Составные операторы (блоки) окружены выражениями parens в ANSI C? - PullRequest
33 голосов
/ 06 августа 2009

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

Например:

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

Я смотрел на ANSI C грамматику , пытаясь выяснить, как этот кусок кода поместился бы в дереве разбора, но у меня ничего не получилось.

Итак, кто-нибудь знает, предписано ли такое поведение стандартом или это просто особенность GCC?

Обновление: Я пробовал с флагом -pedantic, и компилятор теперь выдает мне предупреждение:

warning: ISO C forbids braced-groups within expressions

Ответы [ 2 ]

32 голосов
/ 06 августа 2009

Это называется "фигурная группа внутри выражения".

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

31 голосов
/ 19 сентября 2013

Это недопустимо 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 .

...