2012-03-16 46 views
19

Tôi muốn lấy dữ liệu từ một con trỏ IntPtr vào một mảng byte. Tôi có thể sử dụng mã sau để làm điều đó:IntPtr có thể được đưa vào một mảng byte mà không cần thực hiện một Marshal.Copy không?

IntPtr intPtr = GetBuff(); 
byte[] b = new byte[length]; 
Marshal.Copy(intPtr, b, 0, length); 

Nhưng mã ở trên buộc một hoạt động sao chép từ IntPtr vào mảng byte. Nó không phải là một giải pháp tốt khi dữ liệu trong câu hỏi là lớn.

Có cách nào để truyền IntPtr tới mảng byte không? Ví dụ, sẽ công việc sau đây:

byte[] b = (byte[])intPtr

này sẽ loại bỏ sự cần thiết của hoạt động sao chép.

Ngoài ra: làm thế nào chúng ta có thể xác định độ dài của dữ liệu được trỏ đến bởi IntPtr?

+1

Bạn chắc chắn nên sao chép dữ liệu vì 'IntPtr' trỏ vào * bộ nhớ không được quản lý *! – Yahia

+3

Cảm ơn bạn đã trả lời rất nhanh, nhưng IntPtr đó đã được trả về từ chức năng xuất C++, vì vậy tôi có thể quản lý và xóa nó ở bất cứ đâu mà tôi muốn. Tôi không muốn sao chép dữ liệu vì dữ liệu là bộ đệm video, vì vậy nó rất lớn. Sao chép sẽ làm cho hiệu suất kém. Cảm ơn bạn! – TTGroup

+1

Đó thực sự là không có lý do để đi cho thực hành không an toàn ... bạn thực sự cần sao chép nội dung - có một số phương pháp an toàn để làm như vậy (nhanh hơn những người khác) ... – Yahia

Trả lời

17

Như những người khác đã đề cập, không có cách nào bạn có thể lưu trữ dữ liệu trong được quản lýbyte[] mà không cần sao chép (với cấu trúc hiện tại bạn đã cung cấp *). Tuy nhiên, nếu bạn không thực sự cần cần nó nằm trong bộ đệm được quản lý, bạn có thể sử dụng các hoạt động unsafe để làm việc trực tiếp với bộ nhớ không được quản lý. Nó thực sự phụ thuộc vào những gì bạn cần làm với nó.

Tất cả byte[] và các loại tham chiếu khác được quản lý bởi Bộ gom rác CLR, và đây là những gì có trách nhiệm cấp phát bộ nhớ và deallocation khi nó không còn được sử dụng. Bộ nhớ được chỉ định bởi sự trở lại của GetBuffer là một khối bộ nhớ không được quản lý được cấp phát bởi mã C++ và (chi tiết bộ nhớ/triển khai bộ nhớ sang một bên) về cơ bản hoàn toàn tách biệt với bộ nhớ được quản lý GC của bạn. Do đó, nếu bạn muốn sử dụng loại CLR được quản lý GC (byte[]) để chứa tất cả dữ liệu hiện đang được lưu giữ trong bộ nhớ không được quản lý của bạn được chỉ bởi IntPtr, nó cần được di chuyển (sao chép) vào bộ nhớ mà GC biết. Điều này có thể được thực hiện bằng cách Marshal.Copy hoặc bằng một phương pháp tùy chỉnh sử dụng mã số unsafe hoặc pinvoke hoặc những gì có bạn.

Tuy nhiên, điều đó tùy thuộc vào những gì bạn muốn làm. Bạn đã đề cập đến dữ liệu video của nó. Nếu bạn muốn áp dụng một số biến đổi hoặc bộ lọc cho dữ liệu, bạn có thể làm điều đó trực tiếp trên bộ đệm không được quản lý. Nếu bạn muốn lưu bộ đệm vào đĩa, bạn có thể làm điều đó trực tiếp trên bộ đệm không được quản lý.

Về chủ đề chiều dài, không có cách nào để biết độ dài của bộ đệm không được quản lý trừ khi hàm được cấp phát bộ đệm cũng cho bạn biết độ dài là bao nhiêu. Điều này có thể được thực hiện theo nhiều cách, như các nhà bình luận đã đề cập (trường đầu tiên của cấu trúc, ra paramtere trên phương pháp).

* Cuối cùng, nếu bạn có quyền kiểm soát mã C++, bạn có thể sửa đổi nó để nó không chịu trách nhiệm phân bổ bộ đệm mà nó ghi dữ liệu vào, và thay vào đó được cung cấp con trỏ tới bộ đệm được phân bổ. Sau đó, bạn có thể tạo được quản lýbyte[] trong C#, được phân bổ theo kích thước theo yêu cầu của mã C++ và sử dụng loại GCHandle để ghim và cung cấp con trỏ tới mã C++ của bạn.

+0

Cảm ơn lời giải thích chi tiết của bạn, tôi đã sử dụng mã không an toàn để làm điều đó :) – TTGroup

2

Bạn không thể có mảng được quản lý chiếm bộ nhớ không được quản lý. Bạn có thể sao chép từng phần dữ liệu không được quản lý và xử lý từng đoạn hoặc tạo một lớp UnmanagedArray mất IntPtr và cung cấp một trình chỉ mục sẽ vẫn sử dụng Marshal.Copy để truy cập dữ liệu.

Như @Vinod đã chỉ ra, bạn có thể làm điều này với mã số unsafe. Điều này sẽ cho phép bạn truy cập trực tiếp vào bộ nhớ, sử dụng con trỏ dạng C. Tuy nhiên, bạn sẽ cần phải sắp xếp dữ liệu vào bộ nhớ được quản lý trước khi bạn gọi bất kỳ phương thức .NET không an toàn nào, vì vậy bạn bị giới hạn khá nhiều đối với mã giống C của bạn. Tôi không nghĩ rằng bạn nên bận tâm với điều này ở tất cả, chỉ cần viết mã trong C + +.

+0

Ngay cả với công cụ "không an toàn"? –

+0

Ah, không an toàn. Có, bạn có thể làm điều đó với nội dung không an toàn. Bạn có thực sự muốn những thứ không an toàn không? – zmbq

+0

Không chắc chắn, không phải câu hỏi của tôi :) Nhưng nó sẽ là thú vị để xem làm thế nào điều này * có thể * được thực hiện, ngay cả khi có những lá cờ cảnh báo lớn. –

8

Hãy thử điều này:

byte* b = (byte*)intPtr; 

Yêu cầu unsafe (trong hàm chữ ký, khối, hoặc biên dịch cờ /unsafe).

+5

Bạn nên đề cập đến điều này đòi hỏi từ khóa 'unsafe' trong chữ ký chức năng hoặc trong một cặp dấu ngoặc nhọn:' usafe {...} ' –

+0

Cảm ơn, tôi vừa thử nó. Nhưng trình biên dịch đã ném lỗi khi xây dựng "Con trỏ và bộ đệm kích thước cố định chỉ có thể được sử dụng trong một bối cảnh không an toàn". Tôi không hiểu lỗi này, hãy giải thích cho tôi. Cảm ơn! – TTGroup

+2

Dự án của bạn cần phải được cấu hình để cho phép mã không an toàn, mã được nêu trong câu trả lời cần được bao bọc trong không an toàn (như @MikeBantegui đã nói), và quan trọng nhất, điều này cung cấp cho bạn con trỏ không được quản lý tới bộ nhớ không được quản lý chứ không phải CLR Tham chiếu byte [] – jeffora

1

Kiểm tra trang Code Project này để biết giải pháp làm việc với các mảng không được quản lý.

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