2012-08-06 41 views
5

chúng tôi đang đào bới một số C++/CLI-Mã (Cũ Cú pháp NET Beta) thực sự cũ và là một chút ngạc nhiên khi thấy một cái gì đó như thế này:Tại sao printf hoạt động với chuỗi được quản lý?

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

Chương trình kết quả đầu ra một cách chính xác

Test-String 

Chúng tôi đang tự hỏi, tại sao có thể chuyển nguồn chuỗi được quản lý đến printf - và quan trọng hơn: Tại sao nó hoạt động? Tôi không mong đợi nó có một số tiện-tính năng của trình biên dịch vì những điều sau đây không làm việc:

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

này tạo ra một (bằng cách nào đó dự kiến) biên dịch báo lỗi nói rằng System::String^ không thể được chuyển đổi sang const char*. Vì vậy, giải thích thực sự duy nhất của tôi là chuyển một tham chiếu được quản lý đến một va_list vượt qua tất cả các trình biên dịch kiểm tra và thủ thuật mã gốc vào sử dụng một con trỏ vào vùng quản lý. Kể từ System::String được thể hiện tương tự như một char -Array trong bộ nhớ, printf có thể hoạt động. Hoặc trình biên dịch chuyển đổi thành pin_ptr và chuyển nó tới printf.

Tôi không mong đợi nó sẽ tự động sắp xếp String^ đến char*, vì điều đó sẽ dẫn đến rò rỉ bộ nhớ kém mà không có tham chiếu đến địa chỉ bộ nhớ thực. Chúng tôi biết rằng đây không phải là một giải pháp tốt và các phương pháp marshalling khác nhau được giới thiệu bởi Visual Studio-Phiên bản sau cung cấp một cách tiếp cận tốt hơn nhưng nó sẽ rất thú vị để hiểu những gì đang thực sự xảy ra ở đây.

Cảm ơn!

Trả lời

4

Tôi tin rằng đó là vì trình biên dịch là biến nó thành IL này:

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

nào kết thúc lên như một cuộc gọi pinvoke để printf, vì vậy thời gian chạy đang được một chút lén lút bởi marshalling điều đó cho bạn. Bạn vẫn còn trong một thời gian chạy được quản lý và thời gian chạy sẽ cung cấp marhsalling như một dịch vụ khi cần thiết.


Một số lưu ý:

Dường như clr!GenericPInvokeCalliHelper đang làm nâng này trên x86 NET 4 Workstation CLR.

sau đây không hoạt động

Đó là bởi vì đó là thẳng C++. Nó không có cơ hội để đi qua marshalling vì nó là không cần thiết.

+0

Vì vậy, có lẽ câu hỏi là, * tại sao * là trình biên dịch biến nó thành IL đó? Kể từ khi nào là 'printf' một hàm được quản lý? Tại sao nó P/Gọi nó? Tại sao nó không gọi nó giống như bất kỳ chức năng C++ gốc nào khác? –

+0

@CodyGray Nghi ngờ của tôi là nó chọc lỗ nó bởi vì trình biên dịch thấy một cái gì đó cần phải đi qua marshaller, đầu tiên. Tôi sẽ xác minh và viết một cái gì đó toàn diện hơn trong một chút. – vcsjones

+0

Cảm ơn câu trả lời cho đến nay! Với tôi sự khác biệt thực sự duy nhất giữa strcpy và sprintf liên quan đến chuỗi quản lý là một thực tế là sprintf có một biến arg-list và strcpy thì không. Và có lẽ đó là lý do cho mã IL. – Excelcius

Các vấn đề liên quan