4

这种行为在 C# 中是否有效

public class MyClass
{
    private byte[] data;
    public MyClass()
    {
        this.data = new byte[1024];
    }
    public unsafe byte* getData()
    {
        byte* result = null;
        fixed (byte* dataPtr = data)
        {
            result = dataPtr;
        }
        return result;
    }
}
4

5 回答 5

17

如果您要关闭安全系统,那么您有责任确保程序的内存安全。一旦您这样做,您就需要在没有安全系统帮助的情况下安全地做所有事情。这就是“不安全”的意思。

正如 C# 规范明确指出的那样:

可移动变量的地址只能使用固定语句获得,并且该地址仅在该固定语句的持续时间内保持有效。

您正在获取可移动变量的地址,然后在固定语句的持续时间之后使用它,因此该地址不再有效。因此,您被特别要求不要精确地做您正在做的事情

在您对必须遵循的规则有透彻和深入的了解之前,您不应该编写任何不安全的代码。首先阅读规范的所有第 18 章。

于 2012-04-09T17:14:29.997 回答
11

此代码可以正常编译,但会导致运行时问题。该代码本质上是偷运出指向堆中未固定对象的指针。下一次移动类型的 GCMyClass也会移动data引用,并且任何先前返回的值getData现在都将指向不正确的位置。

var obj = new MyClass();
unsafe byte* pValue = obj.getData();
// Assuming no GC has happened (bad assumption) then this works fine
*pValue = 42;

// Assume a GC has now happened and `obj` moved around in the heap.  The 
// following code is now over writing memory it simply doesn't own
*pValue = 42;

最后一行是否导致应用程序崩溃、覆盖string另一个类型的值或只是将一个值插入一个未初始化的数组中,然后在其他地方搞砸了一个数学问题?你不知道。最好的结果是代码很快就崩溃了,但很可能它会做一些更微妙和邪恶的事情。

于 2012-04-09T16:28:05.307 回答
2

您可以使用该Marshal.StructureToPtr()方法而不是不安全的魔法:)

StructureToPtr将结构的内容复制到 ptr 参数指向的预分配内存块。

Marshal.StructureToPtr 方法(对象、IntPtr、布尔值)

于 2013-12-14T15:05:42.673 回答
1

此代码将不起作用(它会编译但在运行时会导致问题)。一旦固定区域结束,数据就不再固定。

于 2012-04-09T16:28:21.450 回答
0

不,一旦您离开该fixed块, 的值result就不再有效(如果 GC 没有运行,它可能巧合地有效)。

执行此类操作的正确方法是引用byte[]通过 C# 代码访问的非托管内存中的 a,或者将托管数组复制到非托管内存中。

于 2012-04-09T16:30:10.060 回答