2012-08-06 17 views
5

estamos cavando actualmente a través de la muy antigua C++/CLI-Code (sintaxis antigua .NET Beta) y eran un poco sorprendido de ver algo como esto:¿Por qué printf funciona con cadenas gestionadas?

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

El programa emite correctamente

Test-String 

Nos estamos preguntando, ¿por qué es posible pasar la fuente de cadena administrada a printf? Y más importante aún: ¿Por qué funciona? No me esperaba que fuera un poco de comodidad-estelar por el compilador debido a que el siguiente no funciona:

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

Esto produce una (de alguna manera esperada) la compilación de error que indica que System::String^ no se puede convertir en const char*. Así que mi única explicación real es que pasar una referencia administrada a una va_list sobrepasa todas las comprobaciones del compilador y engaña al código nativo para que use un puntero en el montón administrado. Como System::String se representa de forma similar a char -Array en memoria, printf puede funcionar. O el compilador se convierte en pin_ptr y lo pasa a printf.

No espero que marque automáticamente el String^ en char*, porque eso daría como resultado una pérdida de memoria incorrecta sin ninguna referencia a la dirección de memoria real.

Sabemos que esta no es una buena solución y los diversos métodos de clasificación introducidos por las últimas Visual Studio-Versions proporcionan un enfoque mucho mejor, pero sería muy interesante entender lo que realmente está sucediendo aquí.

Gracias!

Respuesta

4

creo que es porque el compilador está convirtiendo en este 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) 

que termina como una llamada a PInvoke printf, por lo que el tiempo de ejecución está siendo un poco disimulado por el cálculo de referencias por usted. Aún se encuentra en un tiempo de ejecución administrado, y el tiempo de ejecución proporcionará marhsalling como servicio cuando sea necesario.


Algunas notas:

Parece que clr!GenericPInvokeCalliHelper está haciendo esto de elevación en el x86 .NET CLR 4 estaciones de trabajo.

la siguiente no funciona

Esto se debe a que es recta C++. No tiene ninguna posibilidad de pasar por el marshalling porque no es necesario.

+0

Así que tal vez la pregunta es, * ¿por qué * es el compilador convirtiéndolo en esa IL? ¿Desde cuándo 'printf' es una función administrada? ¿Por qué es P/Invocarlo? ¿Por qué no lo está llamando como cualquier otra función nativa de C++? –

+0

@CodyGray Mi sospecha es que está invocando porque el compilador ve que algo tiene que pasar primero por el marcador. Verificaré y escribiré algo más completo en un momento. – vcsjones

+0

¡Gracias por las respuestas hasta ahora! Para mí, la única diferencia real entre strcpy y sprintf con respecto a las cadenas administradas es el hecho de que sprintf toma una variable arg-list y strcpy no. Y tal vez esa es la razón del código IL. – Excelcius

Cuestiones relacionadas