1

我有一些unsafeC# 代码无法更改,并且公开了如下方法:

static unsafe void Foo(
    byte* a, int aLength,
    byte* b, int bLength,
    byte* c, int cLength,
    byte* d, int dLength,
    byte* e, int eLength);

我这样称呼这些方法:

static void Bar(
    byte[] a, int aOffset, int aLength,
    byte[] b, int bOffset, int bLength,
    byte[] c, int cOffset, int cLength,
    byte[] d, int dOffset, int dLength,
    byte[] e, int eOffset, int eLength)
{
    fixed (byte* a_ = &a[aOffset])
    fixed (byte* b_ = &b[bOffset])
    fixed (byte* c_ = &c[cOffset])
    fixed (byte* d_ = &d[dOffset])
    fixed (byte* e_ = &e[eOffset])
    {
        Foo(a_, aLength,
            b_, bLength,
            c_, cLength,
            d_, dLength,
            e_, eLength);
    }
}

(为简洁起见,省略了参数验证。)

除非其中一个字节数组的长度为零,否则这很有效。在这种情况下,我得到一个 IndexOutOfRangeException。

指数数组的边界之外。

如何防止异常,最好不要编写大量样板代码,也不要切换fixed到其他东西?

不安全的方法不会读取或写入长度为零的参数。

4

3 回答 3

2

您无法访问空数组中的任何元素,因此将任何空数组替换为包含您可以访问的元素的虚拟数组:

if (aLength == 0) a = new int[1];
if (bLength == 0) b = new int[1];
if (cLength == 0) c = new int[1];
if (dLength == 0) d = new int[1];
if (eLength == 0) e = new int[1];
于 2012-06-02T23:36:35.187 回答
0

static void Bar( ... )
{
  byte[] dummy = new byte[1];
  fixed (byte* a_ = a.Lenght>0 ? &a[aOffset] : &dummy[0])
  ...
}

太笨重?

编辑:

仅出于历史原因保留上述内容,?操作员将无法工作。

所以你需要在没有fixed关键字的情况下做一些类似的事情

public unsafe struct UnsafePointerStruct
{
    public GCHandle gch;
    public byte* addr;
}

static unsafe UnsafePointerStruct GetUnsafePointer(Array a, int ai)
{
    UnsafePointerStruct ups=new UnsafePointerStruct();
    ups.gch=GCHandle.Alloc(a,GCHandleType.Pinned);
    if (a.Length<=ai) ups.addr=(byte*)IntPtr.Zero;
    ups.addr=(byte*)Marshal.UnsafeAddrOfPinnedArrayElement(a,ai);
    return ups;
}

static unsafe void Bar(
    byte[] a, int aOffset, int aLength,
    byte[] b, int bOffset, int bLength,
    byte[] c, int cOffset, int cLength,
    byte[] d, int dOffset, int dLength,
    byte[] e, int eOffset, int eLength)
{
    UnsafePointerStruct upsa=GetUnsafePointer(a,aOffset);
    UnsafePointerStruct upsb=GetUnsafePointer(b,bOffset);
    UnsafePointerStruct upsc=GetUnsafePointer(c,cOffset);
    UnsafePointerStruct upsd=GetUnsafePointer(d,dOffset);
    UnsafePointerStruct upse=GetUnsafePointer(e,eOffset);

    Foo(upsa.addr, aLength,
        upsb.addr, bLength,
        upsc.addr, cLength,
        upsd.addr, dLength,
        upse.addr, eLength);

    upsa.gch.Free();
    upsb.gch.Free();
    upsc.gch.Free();
    upsd.gch.Free();
    upse.gch.Free();
}
于 2012-06-02T23:38:20.380 回答
0

由于它不会读取或写入长度为零的数组,因此您可以更改

fixed (byte* a_ = &a[aOffset])
fixed (byte* b_ = &b[bOffset])
fixed (byte* c_ = &c[cOffset])
fixed (byte* d_ = &d[dOffset])
fixed (byte* e_ = &e[eOffset])

fixed (byte* a_ = (a.Length == 0 ? (byte*)IntPtr.Zero : &a[aOffset]))
fixed (byte* b_ = (b.Length == 0 ? (byte*)IntPtr.Zero : &b[aOffset]))
fixed (byte* c_ = (c.Length == 0 ? (byte*)IntPtr.Zero : &c[aOffset]))
fixed (byte* d_ = (d.Length == 0 ? (byte*)IntPtr.Zero : &d[aOffset]))
fixed (byte* e_ = (e.Length == 0 ? (byte*)IntPtr.Zero : &e[aOffset]))

但是,如果您这样做然后尝试读取或写入其中一个空数组,您将得到一个空指针异常。

于 2012-06-02T23:41:50.667 回答