Laden...

C++ und C# Projekte mischen

Erstellt von zommi vor 15 Jahren Letzter Beitrag vor 15 Jahren 3.803 Views
zommi Themenstarter:in
1.361 Beiträge seit 2007
vor 15 Jahren
C++ und C# Projekte mischen

Hallo an alle,

ich habe gerade probiert C# und C++ Projekt zu mixen.
(der Performance Willen)
Dafür hab ich in eine bestehende Solution (Projektmappe die bisher nur aus C#-Projekten bestand) ein C++ Projekt hinzuzufügen.
(hab folgendes als Template gewählt: C++ CLR-Klassenbibliothek)

Hab zwar Google und Forumssuche bemüht, aber leider nur Beispiele mit COM/DllImport & co gefunden. Wo man Win32-C++ Code aufrufen will.
Aber ich will ja managed c++ code aufrufen (clr compliant). Und da gibs Probleme.

Ich bekomm nen Compilerfehler, wenn ich ne C++ Klassenmethode aufrufen will. Hier mal der Minimal-Code:


//C++ Code (header datei)
public class Class1{
   public:
     void test();
};


//C++ Code (cpp datei)
void Class1::test(){	
...
}


//C# Code
...
Class1 c = new Class1();
...
c.test();   //<-- Hier gibts nen Compilerfehler !!!
...

Der Fehler heißt:


[B]"Addition.Class1" enthält keine Definition für "test", und es konnte keine Erweiterungsmethode "test" gefunden werden, die ein erstes Argument vom Typ "Addition.Class1" akzeptiert. [/B]

Sehr komisch.
Also, dass ja Objekt-Methoden so implementiert sind, dass intern als erster Parameter "this" übergeben wird, ist mir ja bewusst. Aber wo ist hier das Problem? Ich hab doch _test _ als Klassenmethode deklariert!? (Und nix static oder so)

Oder gibs irgendwie Probleme mit cdecl, stdcl...etc?
An fehlenden Namespaces kann es m.E. auch nicht liegen, da ich per Intellisense Class1 sehe als auch den Zugriff über den kompletten Namespace-Namen versucht habe.

Habt ihr ne Idee? (Meine ersten Versuche, was C#/C++ Gemische angeht 😉 )

beste Grüße
zommi

998 Beiträge seit 2007
vor 15 Jahren

Das kann nicht funktionieren weil du dort in C++ eine native Klasse definierst, nicht wie du denkst eine C++ CLI Klasse (die begint mit ref - Referenztyp oder value - wertetyp)...

Wenn du die native C++ Klasse von oben aufrufen willst, mußt du einen CLI-Wrapper dafür schreiben.

Gruß David

zommi Themenstarter:in
1.361 Beiträge seit 2007
vor 15 Jahren

Hey, danke.

die begint mit ref

Das wars. Einfach ein ref davor... und es geht 🙂

Ich hätte nicht gedacht, dass man ob CLI oder nicht, man im Quellcode angibt (eben ob ref/value oder nich) sondern über nen Compiler-Schalter.

Aber gut. Da hats wohl bei mir an den Basics gefehlt.

Ich werd jetzt 2 Klassen nehmen, eine mit ref, die ich ausm c# code aufrufen kann, die intern dann aber die Methoden der anderen "normale" Klasse aufruft.

beste Grüße
zommi

M
198 Beiträge seit 2007
vor 15 Jahren

OT: Du weist aber schon das Managed C++ und C# (und VB.Net) in CIL übersetzt werden -> Alle drei Sprachen sind theoretisch gleich schnell? oder hab ich hier irgendwas übersehen?

Gelöschter Account
vor 15 Jahren

egal in welcher .net sprache. wenn il dabei kompiliert wird ist im endeffekt alles gleich schnell.

zommi Themenstarter:in
1.361 Beiträge seit 2007
vor 15 Jahren

Hallo,

jupjup @ IL = alles gleichschnell,

aber ich will ja in C++ zusätzlich auch nicht-CIL-Code unterbringen.
(Deshalb jetzt ja mein 2 Klassen konzept)

Und so kann ich (analog zu unsafe in C#) maschinennäher, schnellere Algorithmen bauen.

Aber jetzt hab ich noch ein Problemchen:
(bisher erst eine Klasse, die nun auch dank "ref" ne CLI-Klasse sein sollte.)
Wenn ich ne Methode ohne Parameter hab, lässt die sich super aufrufen.
Wenn die Parameter integers sind, klappts auch supi.

Aber wenn ich "echte" Klassen übergeben will. (Wie eine eigene in C# geschriebene), dann kommt wieder ne Fehlermeldung im C#-Block:

//C++
void Class1::test(MyClass c){...}
//C#
Class1 c;
...
c.test(new MyClass()); //<-- Hier kommt die Fehlermeldung, deren Aussage ich nicht verstehe

[B]"test" wird von der Sprache nicht unterstützt.[/B]

Trotzalledem kann ich in der C++-Methode (so macht es mir intellisense glaubhaft) auf alle .Net-Framework Klassen zugreifen und auch (nach namespace einbindung und verweis) auf meine eigenen in C# geschriebenen Klassen.
Nur mit der Parameterübergabe haperts.

beste Grüße
zommi

//PS:
Kann mir jemand für das Thema evtl. einen guten Link geben? n schönes Tut.
Oder zumindest sonstewas, wo mal die CLI-konforme Koexistenz von C#/C++ demonstriert wird?

871 Beiträge seit 2005
vor 15 Jahren

Und so kann ich (analog zu unsafe in C#) maschinennäher, schnellere Algorithmen bauen.

Hallo,

ohne dass ich das jetzt böse mein: Aber wenn Du wirklich des Quäntchen Performance dass Du durch nativ kompilierten Code rausholen könntest benötigst (welches schlimmstenfalls ohnehin durch Interop wieder draufgeht), solltest Du dir vielleicht überlegen ob es nicht sinnvoll wäre den Algorithmus effizienter zu gestalten - und dann direkt in einer CLI Sprache implementieren.

Grüsse,
Egon

/edit: Bezüglich deiner Frage zum Interop

1.) Wenn Du C++ mit /CLI kompilierst kriegst du eine Assembly raus -> Die kannst Du dann direkt Referenzieren und deren Klassen benutzen.
2.) Wenn Du nativ kompilierst musst Du deine C++ Klassen mittels COM ansprechen (Forumssuche)
3.) Du könntest als Einsprungspunkt eine C-Funktion schreiben (als C Export deklarieren: __declspec, siehe MSDN) und von dieser dann aus die C++ Klassen benutzen. Die C Funktion rufst du dann über P/Invoke auf.

998 Beiträge seit 2007
vor 15 Jahren

Der schein trügt, du kannst aus native C++ definitiv nicht ohne weiteres auf .NET Objekte zugreifen, wie auch, der Zeiger im native C++ der auf dein managed Objekt zeigt würde nach kurzer Zeit ins nichts zeigen, da der GC die objekte munter auf dem heap rumsortiert. Lösung schaffen da pinpointer oder interieur pointer (glaub so hießen die), die können ein managed objekt festpinnen oder es "verfolgen".

Das mischen von nativem C++ mit C++/CLI und C# funktioniert erstuanlich gut und dank der unterstützung der STL-Container in C++ 2008 geht nun auch das umkopieren einfach und schnell.

@egrath: Das würde ich so nicht sagen, wenn du beispielweise Grafikalgorithmen implementierst bist du mit nativem Code doch um einiges schneller als wenn du das ganze mit CLI-Code machst.

Ich habe viel mit C++/CLI Interop gemacht und kann dir das Buch "C++/CLI in Action" nur wärmstens empfehlen, das ist das mit abstand beste buch was es zu dem Thema gibt und sollte genau das abdecken, was du da machen möchtest.

Gruß David

zommi Themenstarter:in
1.361 Beiträge seit 2007
vor 15 Jahren

Hallösche,

Bei mir gehts genau um Grafikalgorithmen. Die Algorithmen sind schon gut, nur so ein 1.000.000 großen Integer-Array abzuarbeiten dauert eben auch seine Zeit.
Und mit dem nativen C++ Code umgehe ich komplett die Array-Grenzen-Checks der CLR und habe die Möglichkeit die SSE-Befehlssätze für die Parallelisierung zu nutzen (Und das kann im Idealfall Beschleunigungen von x2, x4 und mehr bringen.)
(Sonst würd ich den ganzen Aufwand ja auch nicht betreiben 😄)

nicht ohne weiteres auf .NET Objekte zugreifen

Ah ok, dann kann man wahrscheinlich nur auf Objekte zugreifen, die intern Werttypen sind, strukturen, die eh "by value" übergeben werden.

Deshalb konnte ich auch ein IntPtr auf mein Array an die Methode übergeben.
Aber nicht das Objekt selbst, dass intern das Array kapselt.
(Ich wollte nämlich den GCHandle/Pinning-Kram auf C++-Seite auslagern)
Aber das wird dann so wohl nix, außer ich nehm diese speziellen Object-pointer.
Klingt auch nicht schlecht.

besten Dank und
beste Grüße
zommi

Gelöschter Account
vor 15 Jahren

Und so kann ich (analog zu unsafe in C#) maschinennäher, schnellere Algorithmen bauen.

nihct ganz. unsafe heißt nur das du mit pointern arbeiten kannst und somit den typesafe bereich verlässt. unsafe code ist dennoch managed und wird auch vom gc überwacht.

siehe->Inside Java and .NET

in deinem fall würde ich auf c# verzichten und nur c++/cli nehmen, da man dort nativen mit managed code besser und perfomanter mixen kann. c# stört da nur. evtl vielleicht nur die gui aber das wars dann auch für c#.

die SSE-Befehlssätze für die Parallelisierung zu nutzen

das macht der jit-compiler mit assemblies in releaseversion. das ist im übrigen die stärke der execution engine. leider ist aber nirgends dokumentiert inwiefern und in welchen fällen diese cpu-spezifischen features z.b. genutzt werden. microsoft scheint sich da auszuschweigen. wenn jemand einen guten link hat dann möge er mir diesen bitte mitteilen.

Und mit dem nativen C++ Code umgehe ich komplett die Array-Grenzen-Checks der CLR

das z.b. kannst du mit unsafe auch erreichen. vorher musst du allerdings das objekt pinnen, wenn es kleiner als 85.000 byte ist.

zommi Themenstarter:in
1.361 Beiträge seit 2007
vor 15 Jahren

Hi JAck30lena,

Und so kann ich (analog zu unsafe in C#) maschinennäher, schnellere Algorithmen bauen.
...
Und mit dem nativen C++ Code umgehe ich komplett die Array-Grenzen-Checks der CLR
das z.b. kannst du mit unsafe auch erreichen. vorher musst du allerdings das objekt pinnen, wenn es kleiner als 85.000 byte ist.

Genau das meinte ich ja 🙂 Mit unsafe kann ich die Array-Grenzen umgehen. kann direkt mit "Pointern" im Speicher arbeitern. Und direkte Hauptspeichermanipulation ist für mich maschinennäher. Und mit C++ geht das natürlich erst recht.

die SSE-Befehlssätze für die Parallelisierung zu nutzen
das macht der jit-compiler mit assemblies in releaseversion

Das hab ich auch gerüchteweise gehört. Aber wie gesagt: Gerüchteweise 😉
Aber selbst ist der Mann. Und handoptimierter Code ist natürlich nicht langsamer, eher schneller 😉

in deinem fall würde ich auf c# verzichten und nur c++/cli nehmen, da man dort nativen mit managed code besser und perfomanter mixen kann. c# stört da nur. evtl vielleicht nur die gui aber das wars dann auch für c#.

Mhhh...aber ich wollte eigentlich nur die absoluten Kerne der Algorithmen so optimieren. Also in der Summe vielleicht so 20-30 Codezeilen. Prinzipiell find ich C# schon schnuckliger 😉 Hab mich aber noch nie ernsthaft mit C++/CLI beschäftigt.

beste Grüße
zommi

Gelöschter Account
vor 15 Jahren

das problem ist, das wenn du z.b. aus c# ein bild in z.b. unmanaged bereich schieben willst, weil dort der algo schneller ist, dann hast du einen gewaltigen overhead beim kopieren des images und zurückkopieren.

was genau möchtest du denn eigendlich machen? was machen die algorithmen

edit: auch in unsfe code werden fleisig exceptions geworfen wenn du mit den pointern hunbug treibst^^
unsafe != typesafe
nicht (wie viele denken) unmanaged. daher ist die ausführungsgeschwindigkeit die selbe. der einzige vorteil in diesem fall ist wohl wirklich (wie du sagst) nur die eingesparte zeit, die die üblichen checks sonst kosten.

ich wollte das nur klarstellen, da man durch das geschriebene falschannahmen machen konnte.

zommi Themenstarter:in
1.361 Beiträge seit 2007
vor 15 Jahren

Hi,

auch in unsfe code werden fleisig exceptions geworfen wenn du mit den pointern hunbug treibst^^

Das mag sein. Darauf hab ichs noch nich ankommen lassen 😉

der einzige vorteil...

Naja, wenn man unsafe n Array durchläuft kann man mit


float* startPtr = ...;
float* endPtr = startPtr + myArray.Length;
for(float* p=startPtr; p<endPtr; p++){
   (*p) *= 1.5f;
}

noch was rauskitzeln 😉

dann hast du einen gewaltigen overhead beim kopieren des images und zurückkopieren.

Warum kopieren? Ich kann doch das Objekt pinnen und dann aus nem nativen C++-Code in diesem Speicher-Bereich direkt rumpfuschen.

Gelöschter Account
vor 15 Jahren

Warum kopieren? Ich kann doch das Objekt pinnen und dann aus nem nativen C++-Code in diesem Speicher-Bereich direkt rumpfuschen.

äh, ich muss zugeben, da ich mich in dem bereich nciht so gut auskenne. vermutlich hast du recht. ich habe bislang gedacht, das man von außerhalb nicht so einfach in managed heap rein kann. andererseits ... wer sollte einen daran hindern...

998 Beiträge seit 2007
vor 15 Jahren

Zoomi hat vollkommen recht, wie ich oben schon schrieb gibt es die pin-pointer, damit kann ich aus nativem C++ ein festgepinntes managed Objekt nach belieben verändern und das ohne controlle der runtime 🙂 Besonders bei Bildern ist das, wie schon gesagt, extremst geil, besonders wenn man Filteroperationen im Ortsbereich macht, die wirklich extremst rechenintensiv sind, besonders bei größeren Filterkernen.

Gruß David

P.S. Das ist wie gesagt alles wunderbar in dem Buch beschrieben.