C#到底有没有指针
起因
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() //调用ToPointer返回void类型的指针
{
return m_value;
}阅读IntPtr源码
看看完整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
{
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;
}
}