2010-12-09 11 views
26

me gustaría que esto funcione, pero no es así:¿Hay aa manera de lograr cierres en C

#include <stdio.h> 

typedef struct closure_s { 
    void (*incrementer)(); 
    void (*emitter)(); 
} closure; 

closure emit(int in) { 

    void incrementer() { 
    in++; 
    } 

    void emitter() { 
    printf("%d\n", in); 
    } 

    return (closure) { 
    incrementer, 
    emitter 
    }; 
} 

main() { 
    closure test[] = { 
    emit(10), 
    emit(20) 
    }; 

    test[0] . incrementer(); 
    test[1] . incrementer(); 

    test[0] . emitter(); 
    test[1] . emitter(); 
} 

En realidad, hace de compilación y de hecho funciona de 1 instancia ... pero el segundo falla ¿Alguna idea de cómo obtener cierres en C?

¡Sería realmente increíble!

Respuesta

14

Usando FFCALL,

#include <callback.h> 
#include <stdio.h> 
static void incrementer_(int *in) { 
    ++*in; 
} 
static void emitter_(int *in) { 
    printf("%d\n", *in); 
} 
int main() { 
    int in1 = 10, in2 = 20; 
    int (*incrementer1)() = alloc_callback(&incrememnter_, &in1); 
    int (*emitter1)() = alloc_callback(&emitter_, &in1); 
    int (*incrementer2)() = alloc_callback(&incrememnter_, &in2); 
    int (*emitter2)() = alloc_callback(&emitter_, &in2); 
    incrementer1(); 
    incrementer2(); 
    emitter1(); 
    emitter2(); 
    free_callback(incrementer1); 
    free_callback(incrementer2); 
    free_callback(emitter1); 
    free_callback(emitter2); 
} 

Pero por lo general en C que acaban de pasar argumentos adicionales en torno a los cierres falsos.


Apple tiene una extensión no estándar para C blocks llamada, que no funciona muy parecido a los cierres.

+0

¿Los bloques no son solo una parte de Objective-C? ¿Puedes compilar C puro como C (y no simplemente ObjC sin objetos o mensajes) y usar bloques? – outis

+1

@outis: Creo que Apple agregó bloques de compatibilidad a GCC y clang en todos los lenguajes relacionados con C, no solo en Objective-C. Pero no tengo una máquina OS X para probarlo. – ephemient

+0

tienes razón. Acabo de probarlo, y funciona en C. puro. No probé C++, pero eso probablemente también funciona. – outis

2

GCC admite funciones internas, pero no cierres. C++ 0x tendrá cierres. Ninguna versión de C que conozco, y ciertamente ninguna versión estándar, proporciona ese nivel de asombroso.

Phoenix, que es parte de Boost, proporciona cierres en C++.

+1

¿Puede pensar en una forma astuta de masajear C para lograr lo que estamos buscando aquí sin contaminar la sintaxis o no necesitar bibliotecas adicionales? Suena tan cerca. – kristopolous

+0

No. Dado que no hay soporte de nivel de idioma, necesitará soporte de biblioteca. Como lo más cercano que puede hacer para ampliar el idioma es usar macros y no hay sobrecarga, necesitará una sintaxis especial, posiblemente oculta detrás de las macros. – outis

+0

Bueno, sé que no es una característica prevista de C --- pero hacer herencia orientada a objetos a través de un montón de estructuras y magia macro tampoco era un uso planificado. El problema es la reutilización del espacio de direcciones y la temporalidad de los indicadores ... La razón clave es simple, "C no es ese tipo de lenguaje". E incluso si obtiene la función privada y la parte variable hacia abajo; que es lo que ofrece OO, todavía le faltan funciones anónimas, un componente principal para hacerlo útil; y eso indudablemente requeriría macros. – kristopolous

7

GCC y el sonido metálico tienen la extensión de bloques, que es esencialmente cierres en C.

+1

Los bloques no están en la línea principal de GCC, solo el tenedor de Apple. – ephemient

+1

Apple ha implementado bloques en la copia propia de Apple de las fuentes GCC y en el front end del compilador Clang LLVM. – Nektarios

1

En esta página usted puede encontrar una descripción sobre cómo hacer cierres en C:

http://brodowsky.it-sky.net/2014/06/20/closures-in-c-and-scala/

La idea es que se necesita una estructura y esa estructura contiene el puntero a la función, pero se proporciona a la función como primer argumento. Además del hecho de que requiere mucho código de placa de caldera y la administración de la memoria es un problema, esto funciona y proporciona el poder y las posibilidades de cierre de otros lenguajes.

2

El ANSI C no tiene un soporte para el cierre, así como funciones anidadas. La solución para esto es el uso simple "struct".

Cierre de ejemplo simple para suma dos números.

// Structure for keep pointer for function and first parameter 
typedef struct _closure{ 
    int x; 
    char* (*call)(struct _closure *str, int y); 
} closure; 


// An function return a result call a closure as string 
char * 
sumY(closure *_closure, int y) { 
    char *msg = calloc(20, sizeof(char)); 
    int sum = _closure->x + y; 
    sprintf(msg, "%d + %d = %d", _closure->x, y, sum); 
    return msg; 
} 


// An function return a closure for sum two numbers 
closure * 
sumX(int x) { 
    closure *func = (closure*)malloc(sizeof(closure)); 
    func->x = x; 
    func->call = sumY; 
    return func; 
} 

Uso:

int main (int argv, char **argc) 
{ 

    closure *sumBy10 = sumX(10); 
    puts(sumBy10->call(sumBy10, 1)); 
    puts(sumBy10->call(sumBy10, 3)); 
    puts(sumBy10->call(sumBy10, 2)); 
    puts(sumBy10->call(sumBy10, 4)); 
    puts(sumBy10->call(sumBy10, 5)); 
} 

Resultado:

10 + 1 = 11 
10 + 3 = 13 
10 + 2 = 12 
10 + 4 = 14 
10 + 5 = 15 

En C++ 11 será achived por la expresión lambda uso.

#include <iostream> 
int main (int argv, char **argc) 
{ 
    int x = 10; 
    auto sumBy10 = [x] (int y) { 
     std::cout << x << " + " << y << " = " << x + y << std::endl; 
    }; 
    sumBy10(1); 
    sumBy10(2); 
    sumBy10(3); 
    sumBy10(4); 
    sumBy10(5); 
} 

A resultado, después de la compilación con un indicador -std = C++ 11.

10 + 1 = 11 
10 + 2 = 12 
10 + 3 = 13 
10 + 4 = 14 
10 + 5 = 15 
Cuestiones relacionadas