C#P/Invoke | blittable结构数组的编组行为不一致?

C#P/Invoke | blittable结构数组的编组行为不一致?,c#,interop,pinvoke,C#,Interop,Pinvoke,今天我在测试p/Invoke的东西,遇到了一些让我非常困惑的东西 我有一个非托管库,其中的函数接受数组参数,打印它们的值并修改它们: #include <cstdio> #define export extern "C" void __cdecl __declspec(dllexport) struct S { int x; }; export PassIntArray(int* x, int size) { for (int i = 0; i < siz

今天我在测试p/Invoke的东西,遇到了一些让我非常困惑的东西

我有一个非托管库,其中的函数接受数组参数,打印它们的值并修改它们:

#include <cstdio>

#define export extern "C" void __cdecl __declspec(dllexport)

struct S
{
    int x;
};

export PassIntArray(int* x, int size)
{
    for (int i = 0; i < size; i++)
    {
        printf("x[%i] = %i\n", i, x[i]);
        x[i] *= 10;
    }
}

export PassSArray(S* s, int size)
{
    for (int i = 0; i < size; i++)
    {
        printf("s[%i].x = %i\n", i, s[i].x);
        s[i].x *= 10;
    }
}
运行此程序时,数组函数的输出如下所示:

// Unmanaged side:
x[0] = 1
x[1] = 2
x[2] = 3
// Managed side, after modification:
10
20
30
但是,对帕萨雷来说,这是:

// Unmanaged side:
s[0].x = 1
s[1].x = 2
s[2].x = 3
// Managed side, after modification:
1
2
3
发件人: “当值可blittable时发生,这是一个昂贵的词,意味着托管值或对象布局与本机布局相同。pinvoke封送器随后可以采取快捷方式,固定对象并将指针传递到托管对象存储。由于本机代码直接修改托管对象,因此您将不可避免地看到更改。”对象。”


根据我的理解,S应该是可空转的(因为它使用顺序布局,并且只包含可空转类型的字段),因此应该由封送员固定,从而导致对“结转”的修改,就像对PassIntArray所做的那样区别在哪里,为什么?

您是否在没有
[In,Out]
的情况下尝试过它?哦,这是从测试中得到的,我没有意识到,当发布[In]似乎是默认行为时,[Out]使所有内容都为0/垃圾值,[In,Out]按照我的要求工作,与int[]一样。我的问题是,为什么没有任何属性的行为是不同的。如果它产生了不同,那会很奇怪。无法完全解释这种行为。胡乱猜测:
int[]
被固定,而
S[]
被复制。@PetSerAl为什么?[输入,输出]属性至少应该防止这种情况,不是吗?
// Unmanaged side:
s[0].x = 1
s[1].x = 2
s[2].x = 3
// Managed side, after modification:
1
2
3