2012-08-06 15 views
5

obecnie kopanie przez jakiś naprawdę starych C++/CLI-Code (Stary Składnia .NET Beta) i były nieco zaskoczony, aby zobaczyć coś takiego:Dlaczego printf działa z zarządzanymi ciągami?

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

Program poprawnie wyprowadza

Test-String 

Zastanawiamy się, dlaczego można przekazać zarządzane źródło ciągu do printf - i co ważniejsze: Dlaczego to działa? Nie spodziewam się, że będzie trochę wygoda-cecha przez kompilator ponieważ następuje nie działa:

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

Daje to (w jakiś sposób oczekiwany) sporządzaniu błąd mówiąc, że System::String^ nie mogą być konwertowane do const char*. Moim jedynym prawdziwym wytłumaczeniem jest to, że przekazanie zarządzanego odwołania do va_list przewyższa wszystkie kontrole kompilatora i powoduje, że natywny kod wykorzystuje wskaźnik do zarządzanej sterty. Ponieważ System::String jest reprezentowany podobnie do char -Array w pamięci, może działać printf. Lub kompilator konwertuje na pin_ptr i przekazuje go do printf.

Nie oczekuję, że automatycznie pobierze sygnał String^ do char*, ponieważ może to spowodować nieszczelny wyciek pamięci bez odniesienia do rzeczywistego adresu pamięci.

Wiemy, że nie jest to dobre rozwiązanie, a różne metody zestawiania wprowadzane przez późniejsze wersje Visual Studio-Versions zapewniają lepsze podejście, ale byłoby bardzo interesująco zrozumieć, co się tutaj dzieje.

Dzięki!

Odpowiedz

4

wierzę, to dlatego, że kompilator jest przekształcając go w tym 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) 

który kończy się jako wezwanie pinvoke do printf, więc środowisko wykonawcze jest bycie trochę podstępne przez punkt etapowy dla ciebie. Nadal jesteś zarządzanym środowiskiem wykonawczym, a środowisko wykonawcze zapewni marhsalling jako usługę, gdy będzie potrzebna.


Kilka uwag:

Wydaje się, że clr!GenericPInvokeCalliHelper robi to podnoszący na x86 .NET CLR 4 Workstation.

dodaje nie działa

to dlatego, że jest prosty C++. Nie ma szansy przejść przez zestawienie, ponieważ nie jest potrzebne.

+0

Może więc pytanie brzmi: * dlaczego * jest kompilatorem zamieniającym go w IL? Od kiedy to 'printf' jest funkcją zarządzaną? Dlaczego to P/Inwokowanie? Dlaczego nie nazywa się tego jak inną natywną funkcją C++? –

+0

@CodyGray Podejrzewam, że to POTWIERDZANIE, ponieważ kompilator widzi, że najpierw musi przejść przez marshaller. Weryfikuję i piszę coś bardziej kompleksowego. – vcsjones

+0

Dzięki za odpowiedzi do tej pory! Jedyna rzeczywista różnica między strcpy i sprintf dotycząca zarządzanych łańcuchów to fakt, że sprintf przyjmuje zmienną arg-list, a strcpy nie. I może to jest powód kodu IL. – Excelcius

Powiązane problemy