You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# P/Invoke中Blittable结构体数组封送行为不一致问题

Why Struct Array Modifications in P/Invoke Don't Sync Back to Managed Code

Great question! The discrepancy you're seeing boils down to default marshaling behavior differences between value-type arrays (like int[]) and struct arrays—even when the struct is blittable. Let me break this down clearly:

The Root Cause

While your S struct is indeed blittable (sequential layout with blittable fields), the .NET marshaler treats struct arrays differently than primitive value-type arrays by default:

  • For int[] (and other primitive value-type arrays), the marshaler pins the managed array's memory directly and passes the raw pointer to unmanaged code. This means any changes the unmanaged function makes are applied directly to the original managed array—no copying involved.
  • For struct arrays like S[], the default behavior is to create a copy of the array in unmanaged memory when calling the function. The unmanaged code modifies this copy, but when the function returns, the marshaler doesn't sync those changes back to the original managed array (it's a one-way "In" direction by default).

The Fix

To get the same two-way sync behavior as the int[] case, you just need to explicitly tell the marshaler that the struct array parameter is both an input and output parameter using the [In, Out] attribute:

Modify your PassSArray P/Invoke declaration like this:

[DllImport("mylib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void PassSArray([In, Out] S[] s, int size);

Optional: Explicit MarshalAs (For Clarity)

If you want to be extra explicit about the marshaling behavior, you can also specify the array type and link it to the size parameter—though this isn't strictly necessary for blittable structs:

[DllImport("mylib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void PassSArray(
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
    [In, Out] S[] s, 
    int size);

Why This Works

Adding [In, Out] tells the marshaler to:

  1. Pin the original managed array's memory (since S is blittable, no copy is needed)
  2. Pass the pointer to unmanaged code
  3. After the function returns, ensure any changes made to the memory are retained in the original managed array

This makes the struct array's behavior identical to the int[] case—non-managed modifications are immediately reflected in the managed code.

Testing the Fix

After updating the declaration, running your code will now output the expected synchronized values:

// Unmanaged side:
s[0].x = 1
s[1].x = 2
s[2].x = 3
// Managed side, after modification:
10 20 30

内容的提问来源于stack exchange,提问作者LunarLambda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:21:43