如何将C# byte[]传递给C语言的char指针?
Hey there! I’ve dealt with exactly this kind of C#/C interop issue for binary data before, so let’s break down how to solve it reliably—whether you need short-term access or long-term shared memory for your cROS library.
First, a critical note: C# byte is an unsigned 8-bit value, so in your C code, you should use unsigned char* instead of char* to avoid unexpected sign-extension bugs. I’ll structure examples around this safer type match.
Option 1: Short-Term Access with unsafe + fixed (Simplest for Synchronous Calls)
If your cROS library only needs access to the byte array during a synchronous function call (no async processing or long-term storage), use C#’s unsafe context and fixed keyword. This pins the managed array in memory so the GC can’t move it while the C code is using it.
C Library Function Declaration
// cROS.h void cROS_ShareData(unsigned char* data, size_t dataLength);
C# Implementation
using System.Runtime.InteropServices; public class CrosInterop { [DllImport("cROS.dll", CallingConvention = CallingConvention.Cdecl)] private static extern void cROS_ShareData(byte* data, int dataLength); public unsafe void ShareByteArray(byte[] byteArray) { if (byteArray == null || byteArray.Length == 0) return; // Pin the array in memory to prevent GC movement fixed (byte* dataPtr = byteArray) { cROS_ShareData(dataPtr, byteArray.Length); } // Array is unpinned here—do NOT let C code hold the pointer beyond this block! } }
Option 2: Temporary Unmanaged Memory (For Longer Synchronous Calls)
If you need to pass the data to C but want to avoid unsafe code, use the Marshal class to copy the managed byte array to unmanaged memory. This is great if you’re working in a context where unsafe isn’t allowed.
C# Implementation
using System.Runtime.InteropServices; public class CrosInterop { [DllImport("cROS.dll", CallingConvention = CallingConvention.Cdecl)] private static extern void cROS_ShareData(IntPtr data, int dataLength); public void ShareByteArray(byte[] byteArray) { if (byteArray == null || byteArray.Length == 0) return; // Allocate unmanaged memory equal to the array size IntPtr unmanagedData = Marshal.AllocHGlobal(byteArray.Length); try { // Copy managed byte[] to unmanaged memory Marshal.Copy(byteArray, 0, unmanagedData, byteArray.Length); // Call your cROS library function cROS_ShareData(unmanagedData, byteArray.Length); } finally { // Always free unmanaged memory to avoid leaks! Marshal.FreeHGlobal(unmanagedData); } } }
Option 3: Long-Term Shared Memory (For Async/Background Processing)
If your cROS library needs to hold onto the data after the C# function returns (e.g., for async processing or shared state), you can’t use the above methods—they either unpin the array or free the memory immediately. Instead, let the C library manage the memory lifecycle.
C Library Code
// cROS.h unsigned char* cROS_AllocateData(size_t dataLength); void cROS_FreeData(unsigned char* data); void cROS_StoreSharedData(unsigned char* data, size_t dataLength); // cROS.c unsigned char* cROS_AllocateData(size_t dataLength) { return (unsigned char*)malloc(dataLength); } void cROS_FreeData(unsigned char* data) { free(data); } void cROS_StoreSharedData(unsigned char* data, size_t dataLength) { // Store the data pointer for later use (e.g., in a global struct or queue) }
C# Implementation
using System.Runtime.InteropServices; public class CrosInterop { [DllImport("cROS.dll", CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr cROS_AllocateData(int dataLength); [DllImport("cROS.dll", CallingConvention = CallingConvention.Cdecl)] private static extern void cROS_FreeData(IntPtr data); [DllImport("cROS.dll", CallingConvention = CallingConvention.Cdecl)] private static extern void cROS_StoreSharedData(IntPtr data, int dataLength); public void ShareLongLivedByteArray(byte[] byteArray) { if (byteArray == null || byteArray.Length == 0) return; // Ask cROS to allocate unmanaged memory IntPtr unmanagedData = cROS_AllocateData(byteArray.Length); if (unmanagedData == IntPtr.Zero) throw new OutOfMemoryException("Failed to allocate memory in cROS library"); try { // Copy managed data to the cROS-allocated memory Marshal.Copy(byteArray, 0, unmanagedData, byteArray.Length); // Pass the data to cROS for long-term storage cROS_StoreSharedData(unmanagedData, byteArray.Length); // Do NOT free the memory here—cROS will handle it when done (call cROS_FreeData later) } catch { // Clean up if something goes wrong cROS_FreeData(unmanagedData); throw; } } }
Key Best Practices
- Avoid
char*for binary data: Always useunsigned char*in C andbyte*/IntPtrin C# to match C#’s unsignedbytetype. - Memory lifecycle is critical: Never let C code hold a pointer to a managed array outside a
fixedblock, and always track unmanaged memory to prevent leaks. - Calling convention consistency: Make sure
CallingConventioninDllImportmatches your C library’s convention (most C libraries useCdecl).
内容的提问来源于stack exchange,提问作者IsmailYC

