Как этот C-код может иметь лямбда

#objective-c #linux #macos #syntax

#c #лямбда

Вопрос:

Этот код:

 #include <stdio.h>

int main()
{
    void (^a)(void) = ^ void () { printf("test"); } ;
    a();
}
 

Скомпилируйте без предупреждения с помощью clang -Weverything -pedantic -std=c89 (версия clang-800.0.42.1) и распечатайте test .

Я не смог найти никакой информации о стандартном C, имеющем lambda, также gcc имеет свой собственный синтаксис для lambda, и было бы странно, если бы они делали это, если бы существовало стандартное решение.

Комментарии:

1. Не удается воспроизвести clang version 3.8.0-2ubuntu4 в Ubuntu 16.04. Сбой с помощью: error: blocks support disabled - compile with -fblocks or pick a deployment target that supports them .

2. Блоки — это расширение clang .

3. C не может иметь этот код. Что-то специфичное для компилятора.

4. Мммм, это пахнет как Objective-C.

5. Можно подумать -pedantic , что with -std=c89 , по крайней мере, выдаст предупреждение для этого нестандартного кода!

Ответ №1:

Такое поведение, по-видимому, характерно для более новых версий Clang и является расширением языка, называемым «блоки».

Статья Википедии о «блоках» C также предоставляет информацию, подтверждающую это утверждение:

Блоки — это нестандартное расширение, добавленное Apple Inc. к реализациям Clang языков программирования C, C и Objective-C, которое использует синтаксис, подобный лямбда-выражению, для создания замыканий в этих языках. Блоки поддерживаются для программ, разработанных для Mac OS X 10.6 и iOS 4.0 , хотя среды выполнения сторонних производителей позволяют использовать их в Mac OS X 10.5 и iOS 2.2 и системах, отличных от Apple.

Акцент выше мой. На странице расширения языка Clang в разделе «Тип блока» дается краткий обзор типа блока:

Как и типы функций, тип блока представляет собой пару, состоящую из типа результирующего значения и списка типов параметров, очень похожих на тип функции. Блоки предназначены для использования так же, как функции, с ключевым отличием в том, что в дополнение к исполняемому коду они также содержат различные привязки переменных к автоматической (стековой) или управляемой (кучной) памяти.

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

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

Вложенные функции в стиле GCC также требуют динамического создания исполняемых файлов при получении адреса вложенной функции. […].

Акцент выше мой.

Ответ №2:

стандарт C вообще не определяет лямбды, но реализации могут добавлять расширения.

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

Вот пример расширения gcc, который реализует замыкания.

 #include <stdio.h>

int(*mk_counter(int x))(void)
{
    int inside(void) {
        return   x;
    }
    return inside;
}

int
main() {
    int (*counter)(void)=mk_counter(1);
    int x;
    x=counter();
    x=counter();
    x=counter();
    printf("%dn", x);
    return 0;
}
 

Комментарии:

1. Код компилируется с помощью -std=c89 -педантично, он не должен быть расширением языка

2. @mantal То, что clang не сообщает о какой-либо диагностике при компиляции с -std=c89 -pedantic помощью, не означает, что «Это не должно быть расширением языка». Может быть, clang -std=c89 -pedantic не объединяет все расширения или конкретная версия, которую вы используете, содержит ошибку. Стандарт C просто не поддерживает lamda.