将指针(即int [])传递给DLL时,“fixed”是否真的可以保证什么?

时间:2009-11-05 21:40:58

标签: c# dllimport unsafe fixed

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

2 个答案:

答案 0 :(得分:11)

更新:此问题是my blog on December 11th 2012的主题。谢谢你提出的好问题!


  

尝试搜索但未找到任何内容

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

  

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

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


  

这是程序员的责任   确保创建指针   固定的陈述不能超越   执行那些陈述。对于   例如,当由指针创建时   固定语句传递给   外部API,它是程序员的   有责任确保API   保留对这些指针的记忆。


  

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

是!

  

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

你没有。正如语言规范所述,你必须永远不要那样做。既然你永远不会这样做,你就不必找到办法绕过它。这就像是在问“我如何从致命的自我中恢复过来?”你没有 - 如果你不想最终死亡,那么一个好的规则就是“不要在第一时间向自己开枪”。

  

或者这是不太可能出现的情况?

您是否可能编写调用违反托管代码规则的DLL的C#程序? 不知道!你告诉我 - 你觉得你可能会想做什么?

答案 1 :(得分:1)

这是我为修复问题所做的课程。它使用AllocHGlobal在非托管中创建一个内存空间,然后将指针包装到该空间。不幸的是,制作这种通用似乎不起作用,因为我无法在void*方法中找到从T转换为this[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);
        }
    }