4

我尝试搜索这个但没有找到任何东西,但是当将 int[] 作为指针传递到本机 DLL 函数时,是否仍然存在 DLL 可以维护对指针的引用的危险,然后尝试在“固定”块终止后再次访问它?如果 GC 移动了您的数组,这不会导致内存访问错误吗?如果是这样,你如何解决这个问题?或者这是一个不太可能的情况?

4

2 回答 2

11

更新: 这个问题是我在 2012 年 12 月 11 日博客的主题。谢谢你的好问题!


试图搜索这个但没有找到任何东西

当您对语言有疑问时,请考虑阅读语言规范。

当将 int[] 作为指针传递给本机 DLL 函数时,是否仍然存在 DLL 可以保持对指针的引用,然后在“固定”块终止后再次尝试访问它的危险?

是的。正如语言规范所述:


程序员有责任确保由固定语句创建的指针在执行这些语句后不会继续存在。例如,当将固定语句创建的指针传递给外部 API 时,程序员有责任确保 API 不保留这些指针的内存。


如果 GC 移动了您的数组,这不会导致内存访问错误吗?

是的!

如果是这样,你如何解决这个问题?

你没有。正如语言规范所述,您必须永远不要这样做。既然你永远不会那样做,你就不必想办法绕过它。这就像问“我如何从致命的射击自己中恢复过来?” 你不会——如果你不想死,那么一条好的规则是“一开始就不要向自己开枪”。

或者这是一个不太可能的情况?

您是否可能编写调用违反托管代码规则的 DLL 的 C# 程序?不知道!你告诉我——这是你认为你可能想做的那种事情吗?

于 2009-11-05T22:34:30.627 回答
1

这是我为解决问题而开设的课程。它使用 AllocHGlobal 在非托管中创建一个内存空间,然后包装一个指向该空间的指针。不幸的是,使这个泛型似乎不起作用,因为我无法在该方法中找到从void*to 转换Tthis[int i]方法。


    unsafe sealed class FixedFloatArray : IDisposable {
        readonly float* _floats;

        internal FixedFloatArray(int size) {
            _floats = (float*)Marshal.AllocHGlobal(sizeof(float) * size);
        }

        internal FixedFloatArray(float[] floats) {
            _floats = (float*)Marshal.AllocHGlobal(sizeof(float) * floats.Length);
            Marshal.Copy(floats, 0, (IntPtr)_floats, floats.Length);
        }

        internal float this[int i] {
            get { return _floats[i]; }
            set { _floats[i] = value; }
        }

        internal void CopyFrom(float[] source, int sourceIndex, int destinationIndex, int length) {
            var memoryOffset = (int)_floats + destinationIndex * sizeof(float);
            Marshal.Copy(source, sourceIndex, (IntPtr)memoryOffset, length);
        }

        internal void CopyTo(int sourceIndex, float[] destination, int destinationIndex, int length) {
            var memoryOffset = (int)_floats + sourceIndex * sizeof(float);
            Marshal.Copy((IntPtr)memoryOffset, destination, destinationIndex, length);
        }

        public static implicit operator IntPtr(FixedFloatArray ffa) {
            return (IntPtr)ffa._floats;
        }

        public void Dispose() {
            Marshal.FreeHGlobal((IntPtr)_floats);
        }
    }
于 2009-11-06T14:37:04.063 回答