2012-08-06 3 views
5

wir derzeit durch einige wirklich alte C++/CLI-Kodex (alte Syntax .NET Beta) und Graben waren etwas überrascht, so etwas zu sehen:Warum arbeitet printf mit verwalteten Strings?

System::String ^source("Test-String"); 
printf("%s", source); 

Das Programm richtig ausgibt

Test-String 

Wir fragen uns, warum ist es möglich, die verwaltete Zeichenfolge Quelle an printf übergeben - und noch wichtiger: Warum funktioniert es? Ich erwarte nicht, es einig Komfort-Funktion durch den Compiler sein, weil die folgenden nicht funktioniert:

System::String ^source("Test-String"); 
char pDest[256]; 
strcpy(pDest, source); 

Dies erzeugt eine (irgendwie erwartet) Kompilierung Fehlermeldung, dass System::String^ nicht zu const char* umgewandelt werden. Meine einzige wirkliche Erklärung ist, dass die Übergabe eines verwalteten Verweises an eine va_list alle Compiler-Prüfungen übertrifft und den nativen Code dazu bringt, einen Zeiger in den verwalteten Heap zu verwenden. Da System::String ähnlich einem char -Array im Speicher dargestellt wird, kann printf funktionieren. Oder der Compiler konvertiert in eine pin_ptr und übergibt diese an printf.

Ich erwarte nicht, dass es automatisch die String^ zu char* marshalieren, denn das würde zu einem schlechten Speicherverlust ohne Bezug auf die tatsächliche Speicheradresse führen.

Wir wissen, dass dies keine gute Lösung ist und die verschiedenen Marshalling-Methoden der späteren Visual Studio-Versionen bieten einen besseren Ansatz, aber es wäre sehr interessant zu verstehen, was hier tatsächlich passiert.

Danke!

Antwort

4

Ich glaube, es liegt daran, dass der Compiler es in diesem IL dreht:

call vararg int32 modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) printf(int8 modopt([mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedByte) modopt([mscorlib]System.Runtime.CompilerServices.IsConst)*, ..., string) 

die zu printf als pinvoke Anruf endet, so dass die Laufzeit ein wenig hinterhältig wird, indem sie es für Sie Rangier. Sie befinden sich immer noch in einer verwalteten Laufzeitumgebung, und die Laufzeitumgebung stellt marhsalling als Dienst zur Verfügung, wenn sie benötigt wird.


Einige Anmerkungen:

Es scheint, dass clr!GenericPInvokeCalliHelper diese Aufhebung auf der x86 .NET 4 Workstation CLR tut.

folgende funktioniert nicht

Das liegt daran, dass gerade C++ ist. Es hat keine Chance, durch Marshalling zu gehen, weil es nicht benötigt wird.

+0

Also ist vielleicht die Frage, * warum * ist der Compiler macht es in diese IL? Seit wann ist 'printf' eine verwaltete Funktion? Warum ist es P/Invoking es? Warum nennt es es nicht wie jede andere native C++ - Funktion? –

+0

@CodyGray Mein Verdacht ist es PInvozieren es, weil der Compiler sieht, dass etwas zuerst durch den Marshaller gehen muss. Ich überprüfe und schreibe etwas umfassender in ein bisschen. – vcsjones

+0

Danke für die Antworten bis jetzt! Für mich ist der einzige wirkliche Unterschied zwischen strcpy und sprintf in Bezug auf verwaltete Zeichenfolgen die Tatsache, dass sprintf eine Variable arg-list und strcpy nicht verwendet. Und vielleicht ist das der Grund für den IL-Code. – Excelcius