4 Stimmen

ANSI C als Kern eines C#-Projekts? Ist das möglich?

Ich schreibe eine NON-GUI-Anwendung, die plattformübergreifend zwischen OS X und Windows funktionieren soll. Ich betrachte die folgende Architektur, weiß aber nicht, ob sie auf der Windows-Seite funktionieren wird:

(Plattformspezifischer Einstiegspunkt) -> ANSI C-Hauptschleife => ANSI C-Modellcode für Datenverarbeitung/Logik => (Plattformspezifische Hilfsprogramme)

Der Hauptteil, den ich in regulärem ANSI C schreiben möchte, weil A) er unabhängig von der Plattform sein sollte, B) ich sehr vertraut mit C bin, C) er die Aufgabe erledigen kann und das gut

(Plattformspezifischer Einstiegspunkt) kann in allem geschrieben werden, was notwendig ist, um die Aufgabe zu erledigen, das ist eine kleine Menge Code, spielt für mich keine Rolle.

(Plattformspezifische Helfer) sind knifflig. Das sind Dinge wie das Parsen von XML, der Zugriff auf Datenbanken, Grafikwerkzeug-Stuff, was auch immer. Dinge, die in C nicht einfach sind. Dinge, die moderne Sprachen/Frameworks kostenlos zur Verfügung stellen. Auf OS X wird dieser Code in Objective-C geschrieben, der mit Cocoa interagiert. Auf Windows denke ich, dass mein bester Einsatz C# ist

Also sieht meine Architektur auf Windows (vereinfacht) so aus

(C# oder C?) -> ANSI C -> C#

Ist das möglich? Einige Gedanken/Vorschläge bisher..

1) Mein C-Core als .dll kompilieren -- das ist in Ordnung, aber es scheint keine Möglichkeit zu geben, meine C#-Helfer aufzurufen, es sei denn, ich kann irgendwie Funktionszeiger erhalten und sie an meinen Kern übergeben, aber das scheint unwahrscheinlich

2) Ein C .exe und ein C# .exe kompilieren und sie über gemeinsamen Speicher oder eine Art IPC kommunizieren lassen. Ich bin dem nicht vollständig abgeneigt, aber es bringt offensichtlich viel Komplexität mit sich, daher scheint es nicht ideal zu sein

3) Anstatt C# zu verwenden, C++ benutzen, das bringt mir einige schöne Datenverwaltungsfunktionen und schönen Hilfscode. Und ich kann es ziemlich einfach mischen. Und die Arbeit, die ich leiste, könnte wahrscheinlich leicht auf Linux portiert werden. Aber ich mag C++ wirklich nicht, und ich möchte nicht, dass es zu einem Fest von Drittanbieter-Bibliotheken wird. Nicht dass es ein großes Problem ist, aber es ist 2010.. alles für die grundlegende Datenverwaltung sollte eingebaut sein. Und die Ausrichtung auf Linux ist wirklich keine Priorität.

Beachten Sie, dass keine "totalen" Alternativen akzeptabel sind, wie in anderen ähnlichen Fragen auf SO vorgeschlagen; Java, RealBasic, Mono.. diese Anwendung ist extrem leistungsintensiv und erfordert Soft-Realtime für Spiel-/Simulationszwecke, hier brauche ich C & Co, um es richtig zu machen (vielleicht Sie nicht, aber ich schon)

6voto

Aren Punkte 52850

Kurze Antwort: Ja. Sie können sehr einfach auf nicht verwalteten Code von .NET aus zugreifen, müssen jedoch Ihre Daten marshalen.

Lange Antwort: Machen Sie es nicht. Kennen Sie das Mono-Projekt? Es ist eine plattformübergreifende Implementierung von .NET. Sie sind ein bisschen hinter Microsoft, bieten aber immer noch eine Lösung an, die für viele funktioniert. Ich empfehle dringend, Code im verwalteten Zustand zu behalten, wenn dies überhaupt möglich ist. Sie vereiteln den Zweck von .NET, wenn Sie hin und her zu C-Code gehen. Dies wird auch dazu beitragen, die Komplexität Ihres Projekts um das Zehnfache zu reduzieren.

Wenn Sie C ANSI für den Zugriff auf Niedrigleitungsebene benötigen, schlage ich vor, eine kleine & gut getestete C ANSI-API zur Verfügung zu stellen, um alle Niedrigleitungsvorgänge in Ihrem .NET-Kern durchzuführen.

C# Core <==> Kleine C ANSI-Hilfsbibliothek

1voto

user368470 Punkte 71

Warum würdest du das nicht alles in C++ machen? Du kannst alle deine Plattformen erreichen und all die Dinge erhalten, die du sagst, dass C nicht hat. C# ist nur für dot net Sachen, c/c++ funktioniert immer noch unter Windows, hol dir einfach den API-Aufruf, den du für das benötigst, was du versuchst zu tun.

1voto

Qwertie Punkte 14996

Ich mag Arens Antwort (schau dir Mono an), aber wenn du wirklich C + C# verwenden möchtest, kannst du SWIG verwenden, um Wrapper für C-Code weitgehend automatisch zu erstellen. Es hat eine steile Lernkurve, aber wenn die Anzahl der C-Funktionen, die du aus C# aufrufen möchtest, groß genug ist, lohnt sich der Aufwand. SWIG unterstützt Objective C nicht out-of-the-box, aber es gibt einen Zweig mit nicht ganz fertiger Unterstützung.

Update: oh, du möchtest hauptsächlich C# aus C aufrufen? Tut mir leid, SWIG ist dafür nicht wirklich ausgelegt. C# erlaubt es jedoch. Du kannst entweder einen C# oder C/C++ Einstiegspunkt verwenden (ein C# Einstiegspunkt ist wahrscheinlich einfacher), und du kannst Zeiger auf C#-Funktionen (Delegates) an C-Code übergeben.

Angenommen, du möchtest eine void(string) Funktion von C# nach C übergeben. Ich weiß nicht, wie C-Code direkt Zeiger auf C#-Funktionen erhalten kann (es ist möglicherweise möglich, ich weiß es nur nicht.) Stattdessen würde ich das Programm im C#-Code starten und den C#-Code sich selbst an den C-Code übergeben lassen.

Etwa so:

// Visual C-Code:
// (.NET-Funktionen verwenden standardmäßig das __stdcall-Aufrufkonvention.)
typedef void (__stdcall *Callback)(PCWSTR);
void __declspec(dllexport) Foo(Callback c)
{
    c(L"Hallo Welt");
}

// C#-Code:
// (Eine Delegaten-Deklaration kann Marshaling-Befehle enthalten, die
// steuern, wie Argumenttypen konvertiert werden.)
public delegate void Callback([MarshalAs(UnmanagedType.LPWStr)] string nachricht);
void PrintOut(string nachricht) { Console.WriteLine(nachricht); }

Hier haben wir eine C-Funktion "Foo", die einen Zeiger auf die C#-Funktion "PrintOut" (oder eine C-Funktion) empfangen kann, plus eine Callback-Typdefinition. Wir verwenden __declspec(dllexport), damit der C#-Code darauf zugreifen kann.

Auf der C#-Seite haben wir eine Delegaten-Deklaration, die ungefähr analog zur Typdefinition in C ist, und eine Funktion "PrintOut", die wir an C übergeben möchten.

Angenommen, du kompilierst deinen C-Code in eine DLL namens Foo.dll, du benötigst eine C# P/Invoke-Deklaration und Code, der tatsächlich Foo aufruft:

[DllImport("Foo")]
public static extern void Foo(Callback c);

public void CallFoo()
{
    Foo(PrintOut);
}

Das oben genannte wird wahrscheinlich zunächst funktionieren, aber es gibt eine "Falle": der obige Code umschließt PrintOut in einem Delegaten, und der Garbage Collector wird den Delegaten irgendwann freigeben, es sei denn, du behältst eine Referenz darauf. Wenn du also möchtest, dass der C-Code eine dauerhafte Referenz auf die C#-Methode hat, müssen wir den obigen C#-Code so ändern, dass er eine Referenz auf den Delegaten behält:

[DllImport("Foo")]
public static extern void Foo(Callback c);

static Callback PrintOutRef; // um die garbage collection des Delegaten zu verhindern

public void CallFoo()
{
    Foo(PrintOutRef = PrintOut);
}

Hoffe das hilft!

1voto

Pavel Minaev Punkte 97251

Zunächst einmal, um eine spezifische Sorge zu beantworten: Sie können Delegaten als Funktionszeiger zu Ihrem nativen C-Code marshalling - tatsächlich funktioniert es "einfach" und P/Invoke kümmert sich um alles Verpacken:

// C#
class ManagedEntryPoint {

    [DllImport("core", CallingConvention=CallingConvention.Cdecl)]
    static extern void NativeEntryPoint(Func helper);

    static float Helper(int, int) { ... }

    static void Main() {
        NativeEntryPoint(Helper);
    }
}

// C
void NativeEntryPoint(float (*helper)(int, int)) {
    float x = helper(1, 2);
    ...
}

Allerdings sehe ich keinen großen Sinn darin - es ist einfacher, den C++/CLI-Compiler zu verwenden. Beachten Sie, dass dies nicht bedeutet, dass Sie tatsächlich C++ verwenden müssen - Sie können sich auf den Teil von C beschränken, der mit C++ kompatibel ist, was 95 % davon ausmacht (ich würde erwarten, dass Sie in der Praxis nur etwas Anders machen müssen ist das explizite Casten des Rückgabewerts von malloc). Sie kompilieren Ihre nativen C-Funktionen als nativen .lib und verknüpfen dann diese mit einem mit /clr kompilierten ausführbaren Datei. C++/CLI übernimmt das Marshalling selbst und Sie müssen keine P/Invoke-Deklarationen und dergleichen schreiben.

0voto

Puppy Punkte 141483

Es gibt überhaupt keinen Grund, ANSI C gegenüber C++ zu verwenden. Außerdem ist es sehr trivial (so weit ich weiß), wenn Sie C++-Code haben, einen C++/CLI-Wrapper zum Gebrauch in C# zu schreiben, und C++ wird zwei Floats nicht langsamer hinzufügen als C (viele andere Operationen sind tatsächlich schneller, wie z.B. Sortieren). Zudem ist C++ ziemlich flexibel, was Sie damit machen können.

C++ <--> C++/CLI <--> C# ist wahrscheinlich der einfachste Weg, da C++/CLI-Interop problemlos in beide Richtungen funktionieren kann.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X