2013-07-16 27 views
7

này hoạt động:Làm thế nào để sắp xếp lại chuỗi ANSI thông qua thuộc tính?

[DllImport("SDL2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GetError")] 
private static extern IntPtr SDL_GetError(); 

public static string GetError() 
{ 
    return Marshal.PtrToStringAnsi(SDL_GetError()); 
} 

này tai nạn:

[DllImport("SDL2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GetError")] 
[return: MarshalAs(UnmanagedType.LPStr)] 
public static extern string GetError(); 

This article gợi ý rằng thuộc tính trở lại về cơ bản cũng giống như gọi Marshal.PtrToStringAnsi, vì vậy thương vụ này là những gì?


Vì Daniel pointed out, nó có thể bị lỗi vì trình khắc phục sự cố đang cố giải phóng bộ nhớ. Bài báo cũng nêu rõ,

N.B. : Lưu ý rằng bên không được quản lý không được sử dụng từ khóa “mới” hoặc hàm “malloc()” C để cấp phát bộ nhớ. Các Marshoper Interop sẽ không thể giải phóng bộ nhớ trong những tình huống này. Điều này là do từ khóa "mới" phụ thuộc vào trình biên dịch và hàm "malloc" là phụ thuộc vào thư viện C.

Tôi đã thử giải phóng con trỏ char bằng Marshal.FreeHGlobal, Marshal.FreeCoTaskMemMarshal.FreeBSTR - tất cả đều bị lỗi. Không có cách nào khác để giải phóng bộ nhớ AFAIK, vì vậy tôi đoán bộ nhớ đã được cấp phát qua new hoặc malloc(). Vì vậy, những gì bây giờ, tôi hooped? Tôi bị rò rỉ bộ nhớ vĩnh viễn trong chương trình của tôi?

Tôi đã kiểm tra nguồn. Chuỗi được tạo thông qua static char errmsg[SDL_ERRBUFIZE]. C của tôi là gỉ, nhưng tôi đoán nó được tuyên bố là static để nó không được giải phóng khi nó đi ra khỏi phạm vi chức năng. Tôi không nhớ nơi các mảng tĩnh sống trong vùng bộ nhớ mặc dù; có cách nào để giải phóng chúng không?

Chỉnh sửa: Chờ ... nó tĩnh. Điều đó có nghĩa là mỗi lần có một lỗi mới, nó sẽ ghi đè thông báo lỗi cũ, do đó tại sao SDL_GetError() chỉ trả về thông báo lỗi gần đây nhất. Ergo, tôi không phải lo lắng về việc giải phóng nó.

Như vậy, nếu tất cả các tùy chọn return: MarshalAs... cố gắng giải phóng bộ nhớ, thì giải pháp duy nhất là giải pháp hiện tại của tôi. Điều này là tối ưu sau khi tất cả.

+0

Có, nếu nó là tĩnh, thì bộ nhớ không được giải phóng. Vì vậy, cách duy nhất là sắp xếp thủ công, vì nếu không thì trình khắc phục sự cố CLR sẽ giải phóng bộ nhớ. –

Trả lời

3

Tôi đã thực hiện một số thao tác đào. Nguồn cho SDL_GetError là:

const char * 
SDL_GetError(void) 
{ 
    static char errmsg[SDL_ERRBUFIZE]; 

    return SDL_GetErrorMsg(errmsg, SDL_ERRBUFIZE); 
} 

Chúng ta có thể thấy rằng bộ nhớ cho chuỗi được phân bổ như một mảng char tĩnh. Nó được ghi đè mỗi khi SDL_GetError được gọi. Như vậy chúng tôi không thể và không cần phải giải phóng nó.

Vì phương pháp [return: MarshalAs.*] tất cả đều cố gắng giải phóng bộ nhớ sau khi sửa đổi loại, chúng sẽ không hoạt động (và tiếp tục khiến chương trình bị lỗi).

Như vậy, giải pháp ban đầu (của tôi) là tối ưu.

4

Như đã nêu trong bài viết được liên kết, khi sử dụng [return: MarshalAs(UnmanagedType.LPStr)], bộ nhớ của chuỗi gốc được giải phóng bởi CLR sử dụng FreeCoTaskMem(). Nếu bạn tự tạo đối tượng chuỗi được quản lý qua Marshal.PtrToStringAnsi(), bộ nhớ sẽ không được giải phóng.

Nếu sự cố xảy ra, có thể chuỗi không được tạo trên mặt không được quản lý qua CoTaskMemAlloc(), nhưng thông qua new() hoặc malloc() (ví dụ). API của SDL_GetError() nên nêu rõ công việc của họ là giải phóng chuỗi gốc và cách thực hiện.

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