CSharp 到底有没有指针

起因

C#是有指针的,只不过要先标记unsafe,在Rust语言中也是通过unsafe标记,指针在C#越来越重要,尤其在.Net Core中使用指针也更多,在.Net Core是Unsafe类,有更多指针的操作.

unsafe并不是不安全的,只是通过unsafe标记后,该函数或这该代码块区域,内存管理由我们开发人员自己掌控(内存资源的分配和释放),在c#中,GC不管理该区域的内存.

先看看使用指针的代码

unsafe
{
     byte* pIn = (byte*)srcData.Scan0.ToPointer();
     byte* pOut = (byte*)dstData.Scan0.ToPointer();
     int stride = srcData.Stride;
     byte* p;
     //省略
     //XXX
}

Scan0是个句柄(Intptr),通过ToPointer返回一个void *指针,在转换为byte*指针.

来看看ToPointer函数内部

[SecurityCritical]
private unsafe void* m_value;

[SecuritySafeCritical]
[CLSCompliant(false)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[NonVersionable]
public unsafe void* ToPointer()
{
    return m_value;
}
看看完整IntPtr句柄源码,去除一些特性标签
    [Serializable]
    public struct IntPtr : ISerializable
    {
        [System.Security.SecurityCritical]
        unsafe private void* m_value; // The compiler treats void* closest to uint hence explicit casts are required to preserve int behavior

        public static readonly IntPtr Zero;

        // fast way to compare IntPtr to (IntPtr)0 while IntPtr.Zero doesn't work due to slow statics access
        internal unsafe bool IsNull()
        {
            return (this.m_value == null);
        }

        public unsafe IntPtr(int value)
        {
#if WIN32
            m_value = (void*)value;
#else
            m_value = (void*)(long)value;
#endif
        }

        public unsafe IntPtr(long value)
        {
#if WIN32
            m_value = (void*)checked((int)value);
#else
            m_value = (void*)value;
#endif
        }

        public unsafe IntPtr(void* value)
        {
            m_value = value;
        }

        private unsafe IntPtr(SerializationInfo info, StreamingContext context)
        {
            long l = info.GetInt64("value");

            if (Size == 4 && (l > Int32.MaxValue || l < Int32.MinValue))
            {
                throw new ArgumentException(Environment.GetResourceString("Serialization_InvalidPtrValue"));
            }

            m_value = (void*)l;
        }

        public unsafe override bool Equals(Object obj)
        {
            if (obj is IntPtr)
            {
                return (m_value == ((IntPtr)obj).m_value);
            }
            return false;
        }

        public unsafe override int GetHashCode()
        {
            return unchecked((int)((long)m_value));
        }

        public unsafe int ToInt32()
        {
#if WIN32
            return (int)m_value;
#else
            long l = (long)m_value;
            return checked((int)l);
#endif
        }

        public unsafe long ToInt64()
        {
#if WIN32
            return (long)(int)m_value;
#else
            return (long)m_value;
#endif
        }

        public unsafe override String ToString()
        {
#if WIN32
            return ((int)m_value).ToString(CultureInfo.InvariantCulture);
#else
            return ((long)m_value).ToString(CultureInfo.InvariantCulture);
#endif
        }

        public unsafe String ToString(String format)
        {
#if WIN32
            return ((int)m_value).ToString(format, CultureInfo.InvariantCulture);
#else
            return ((long)m_value).ToString(format, CultureInfo.InvariantCulture);
#endif
        }

        public static explicit operator IntPtr(int value)
        {
            return new IntPtr(value);
        }

        public static explicit operator IntPtr(long value)
        {
            return new IntPtr(value);
        }

        public static unsafe explicit operator IntPtr(void* value)
        {
            return new IntPtr(value);
        }

        public static unsafe explicit operator void*(IntPtr value)
        {
            return value.m_value;
        }

        public unsafe static explicit operator int(IntPtr value)
        {
#if WIN32
            return (int)value.m_value;
#else
            long l = (long)value.m_value;
            return checked((int)l);
#endif
        }

        public unsafe static explicit operator long(IntPtr value)
        {
#if WIN32
            return (long)(int)value.m_value;
#else
            return (long)value.m_value;
#endif
        }

        public unsafe static bool operator ==(IntPtr value1, IntPtr value2)
        {
            return value1.m_value == value2.m_value;
        }

        public unsafe static bool operator !=(IntPtr value1, IntPtr value2)
        {
            return value1.m_value != value2.m_value;
        }

        public static IntPtr Add(IntPtr pointer, int offset)
        {
            return pointer + offset;
        }

        public static IntPtr operator +(IntPtr pointer, int offset)
        {
#if WIN32
            return new IntPtr(pointer.ToInt32() + offset);
#else
            return new IntPtr(pointer.ToInt64() + offset);
#endif
        }

        public static IntPtr Subtract(IntPtr pointer, int offset)
        {
            return pointer - offset;
        }

        public static IntPtr operator -(IntPtr pointer, int offset)
        {
#if WIN32
            return new IntPtr(pointer.ToInt32() - offset);
#else
            return new IntPtr(pointer.ToInt64() - offset);
#endif
        }

        public static int Size
        {
            get
            {
#if WIN32
                return 4;
#else
                return 8;
#endif
            }
        }

        public unsafe void* ToPointer()
        {
            return m_value;
        }
    }


秋风 2020-01-15