2010-12-09 5 views
26

ich dies möchte arbeiten, aber es funktioniert nicht:Gibt es aa Weg Schließungen in C zu erreichen

#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(); 
} 

Es tatsächlich tut Kompilierung und funktioniert für 1 Instanz ... aber der zweite schlägt fehl. Irgendeine Idee, wie man Schließungen in C bekommt?

Es wäre wirklich toll!

Antwort

14

FFCALL Verwendung,

#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); 
} 

Aber in der Regel in C beenden Sie zusätzliche Argumente um zu fälschen Schließungen vorbei auf.


Apple hat eine Nicht-Standard-Erweiterung C genannt blocks, die wie Verschlüsse viel arbeiten.

+0

Sind Blöcke nicht nur ein Teil von Objective-C? Können Sie reines C als C kompilieren (und nicht einfach ObjC ohne Objekte oder Messaging) und Blöcke verwenden? – outis

+1

@outis: Ich glaube, dass Apple Blöcke Unterstützung für GCC und Clang in allen C-verwandten Sprachen, nicht nur Objective-C hinzugefügt hat. Aber ich habe kein OS X-Gerät, um es zu testen. – ephemient

+0

Sie haben Recht. Ich habe es getestet und es funktioniert in reinem C. Ich habe C++ nicht getestet, aber das funktioniert wahrscheinlich auch. – outis

2

GCC unterstützt innere Funktionen, aber keine Schließungen. C++ 0x wird Closures haben. Keine Version von C, von der ich weiß, und sicherlich keine Standardversion, bietet dieses Level von großartig.

Phoenix, die Teil von Boost ist, bietet Closures in C++.

+1

Können Sie sich eine schlaue Methode vorstellen, C zu erreichen, um das zu erreichen, wonach wir suchen, ohne die Syntax zu belasten oder zusätzliche Bibliotheken zu benötigen? Es klingt so nah. – kristopolous

+0

Nein. Da keine Unterstützung auf Sprachenebene vorhanden ist, benötigen Sie Unterstützung für die Bibliothek. Da es am nächsten kommt, die Sprache selbst zu erweitern, ist die Verwendung von Makros, und es gibt keine Überladung. Sie benötigen eine spezielle Syntax, die möglicherweise hinter Makros verborgen ist. – outis

+0

Nun, ich weiß, dass es kein beabsichtigtes Merkmal von C ist - aber objektorientierte Vererbung durch eine Reihe von Struct- und Macromagie war auch keine geplante Verwendung. Das Problem ist die Wiederverwendung von Adressraum und die Zeitlichkeit der Zeiger ... Der Hauptgrund ist einfach, "C ist nicht diese Art von Sprache". Und selbst wenn Sie die private Funktion und den variablen Teil abschalten; Was OO bietet, fehlt es immer noch an anonymen Funktionen - ein wichtiger Bestandteil, um es nützlich zu machen; und das würde zweifellos Makros erfordern. – kristopolous

7

GCC und Klirren haben die Erweiterungsblocks, die im Wesentlichen Schließungen in C.

+1

Blöcke sind nicht in GCC Mainline, nur Apples Gabel. – ephemient

+1

Apple hat Blöcke in Apples eigener Kopie der GCC-Quellen und im Clang-LLVM-Compiler-Frontend implementiert. – Nektarios

1

Auf dieser Seite finden Sie eine Beschreibung zu finden, wie Verschlüsse in C zu tun:

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

Die Idee ist, dass eine Struktur benötigt wird und diese Struktur den Funktionszeiger enthält, aber der Funktion als erstes Argument zur Verfügung gestellt wird. Abgesehen von der Tatsache, dass es eine Menge Code von Kesselplatten erfordert und die Speicherverwaltung natürlich ein Problem ist, funktioniert dies und bietet die Macht und die Möglichkeiten der Schließung anderer Sprachen.

2

Das ANSI C unterstützt nicht die Schließung sowie verschachtelte Funktionen. Workaround dafür ist Verwendung einfach "struct".

Einfaches Beispiel Schließung für Summe zwei Zahlen.

// 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; 
} 

Verbrauch:

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)); 
} 

Ergebnis:

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

auf C++ 11 wird es durch die Verwendung Lambda-Ausdruck achived werden.

#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); 
} 

Ein Ergebnis, nach der Kompilierung mit einem Flag -std = C++ 11.

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