2012-08-06 9 views
5

stiamo scavando attraverso alcuni veramente vecchio C++/CLI-Code (Beta vecchia sintassi .NET) ed erano un po 'sorpreso di vedere qualcosa di simile:Perché printf funziona con stringhe gestite?

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

Il programma stampa correttamente

Test-String 

Ci chiediamo, perché è possibile passare la sorgente di stringhe gestite a printf - e ancora più importante: Perché funziona? Non mi aspetto che sia un po 'la convenienza di funzionalità dal compilatore perché il seguente non funziona:

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

Questo produce una (in qualche modo atteso) la compilazione di errore che dice che System::String^ non possono essere convertiti in const char*. Quindi la mia unica spiegazione è che il passaggio di un riferimento gestito a una va_list supera tutti i controlli del compilatore e induce il codice nativo a utilizzare un puntatore nell'heap gestito. Poiché System::String è rappresentato come un char -Array in memoria, printf potrebbe funzionare. Oppure il compilatore converte in pin_ptr e lo passa a printf.

Non mi aspetto che esegua il marshalling automatico dello String^ su char*, perché ciò comporterebbe una perdita di memoria non valida senza alcun riferimento all'indirizzo di memoria effettivo.

Sappiamo che questa non è una buona soluzione e i vari metodi di marshalling introdotti dalle versioni successive di Visual Studio forniscono un approccio migliore, ma sarebbe molto interessante capire cosa sta realmente accadendo qui.

Grazie!

risposta

4

Credo che sia perché il compilatore si sta trasformando in questo IL:

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

che finisce come una chiamata PInvoke per printf, in modo che il tempo di esecuzione è essere un po 'subdolo da smistamento per voi. Sei ancora in un runtime gestito e il runtime fornirà il servizio di Marhsalling quando è necessario.


Alcune note:

Sembra che clr!GenericPInvokeCalliHelper sta facendo sollevamento sul x86 .NET 4 Workstation CLR.

quanto segue non funziona

Ecco perché è dritto C++. Non ha alcuna possibilità di effettuare lo smistamento perché non è necessario.

+0

Quindi forse la domanda è, * perché * il compilatore lo trasforma in IL? Da quando 'printf' è una funzione gestita? Perché è P/invocandolo? Perché non lo chiama come qualsiasi altra funzione C++ nativa? –

+0

@CodyGray Il mio sospetto è che lo stiate invocando perché il compilatore vede qualcosa che deve passare attraverso il marshaller, per prima cosa. Verificherò e scriverò qualcosa di più completo in un po '. – vcsjones

+0

Grazie per le risposte finora! Per me l'unica vera differenza tra strcpy e sprintf riguardo le stringhe gestite è il fatto che sprintf accetta una variabile arg-list e strcpy no. E forse questa è la ragione per il codice IL. – Excelcius

Problemi correlati