为什么不';t IntPtr需要unsafe关键字
本文关键字:需要 unsafe 关键字 IntPtr 为什么不 | 更新日期: 2023-09-27 18:00:27
当您在C#中使用类似int*
的指针时,您需要使用unsafe
关键字,但当您使用IntPtr
时,您不需要。这些有什么区别?他们都可以指向一个地址。
垃圾收集器如何处理这两种类型?他们的处理方式不同吗?如果是,有什么区别?如果没有,为什么需要unsafe
关键字?
编辑:非常感谢大家到目前为止的回答,但我想知道的是框架和垃圾收集器如何以不同的方式处理它们,而不是MSDN对IntPtr
的定义。只需要一次谷歌搜索就可以到达那里。我想知道为什么IntPtr不需要unsafe
关键字?我想了解一下为什么我们可以在没有关键字的情况下使用它。
根据MSDN:
http://msdn.microsoft.com/en-gb/library/system.intptr(v=vs.100).aspx
它只是"指针或句柄"的表示
我一直在阅读GC如何与其他托管类型不同地处理IntPtr
,并且我没有发现任何文档或文章表明IntPtr
的收集方式有任何不同,即一旦IntPtr
超出范围,它就可能是GC’d。
关于为什么没有使用unsafe
关键字阅读已接受的答案,特别是更新:
不安全代码对安全代码有影响吗?
IntPtr
的实现中已经指定了unsafe
(请参阅下面IntPtr
实现中的字段声明),因此使用IntPtr
的类不必将其使用的IntPtr
的任何使用标记为unsafe
,否则它将一直级联到其他类,这些类可能在实现中使用具有不安全代码的类型。
除了unsafe
代码不是IntPtr
之外,字段private unsafe void* m_value;
是unsafe
,您没有直接使用它
// Type: System.IntPtr
// Assembly: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// Assembly location: C:'Windows'Microsoft.NET'Framework'v4.0.30319'mscorlib.dll
using System.Globalization;
using System.Runtime;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security;
namespace System
{
[ComVisible(true)]
[__DynamicallyInvokable]
[Serializable]
public struct IntPtr : ISerializable
{
[SecurityCritical]
private unsafe void* m_value;
public static readonly IntPtr Zero;
[__DynamicallyInvokable]
public static int Size
{
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), __DynamicallyInvokable] get
{
return 4;
}
}
[SecuritySafeCritical]
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[__DynamicallyInvokable]
public IntPtr(int value)
{
this.m_value = (void*) value;
}
[SecuritySafeCritical]
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[__DynamicallyInvokable]
public IntPtr(long value)
{
this.m_value = (void*) checked ((int) value);
}
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[SecurityCritical]
[CLSCompliant(false)]
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public IntPtr(void* value)
{
this.m_value = value;
}
[SecurityCritical]
private IntPtr(SerializationInfo info, StreamingContext context)
{
long int64 = info.GetInt64("value");
if (IntPtr.Size == 4 && (int64 > (long) int.MaxValue || int64 < (long) int.MinValue))
throw new ArgumentException(Environment.GetResourceString("Serialization_InvalidPtrValue"));
this.m_value = (void*) int64;
}
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public static explicit operator IntPtr(int value)
{
return new IntPtr(value);
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
public static explicit operator IntPtr(long value)
{
return new IntPtr(value);
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[SecurityCritical]
[CLSCompliant(false)]
public static explicit operator IntPtr(void* value)
{
return new IntPtr(value);
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[SecuritySafeCritical]
[CLSCompliant(false)]
public static explicit operator void*(IntPtr value)
{
return value.ToPointer();
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[SecuritySafeCritical]
public static explicit operator int(IntPtr value)
{
return (int) value.m_value;
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[SecuritySafeCritical]
public static explicit operator long(IntPtr value)
{
return (long) (int) value.m_value;
}
[SecuritySafeCritical]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public static bool operator ==(IntPtr value1, IntPtr value2)
{
return value1.m_value == value2.m_value;
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[SecuritySafeCritical]
public static bool operator !=(IntPtr value1, IntPtr value2)
{
return value1.m_value != value2.m_value;
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
public static IntPtr operator +(IntPtr pointer, int offset)
{
return new IntPtr(pointer.ToInt32() + offset);
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
public static IntPtr operator -(IntPtr pointer, int offset)
{
return new IntPtr(pointer.ToInt32() - offset);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SecuritySafeCritical]
internal unsafe bool IsNull()
{
return (IntPtr) this.m_value == IntPtr.Zero;
}
[SecurityCritical]
unsafe void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
throw new ArgumentNullException("info");
info.AddValue("value", (long) (int) this.m_value);
}
[SecuritySafeCritical]
[__DynamicallyInvokable]
public override unsafe bool Equals(object obj)
{
if (obj is IntPtr)
return this.m_value == ((IntPtr) obj).m_value;
else
return false;
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[SecuritySafeCritical]
[__DynamicallyInvokable]
public override unsafe int GetHashCode()
{
return (int) this.m_value;
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[SecuritySafeCritical]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[__DynamicallyInvokable]
public unsafe int ToInt32()
{
return (int) this.m_value;
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[SecuritySafeCritical]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[__DynamicallyInvokable]
public unsafe long ToInt64()
{
return (long) (int) this.m_value;
}
[SecuritySafeCritical]
[__DynamicallyInvokable]
public override unsafe string ToString()
{
return ((int) this.m_value).ToString((IFormatProvider) CultureInfo.InvariantCulture);
}
[SecuritySafeCritical]
[__DynamicallyInvokable]
public unsafe string ToString(string format)
{
return ((int) this.m_value).ToString(format, (IFormatProvider) CultureInfo.InvariantCulture);
}
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public static IntPtr Add(IntPtr pointer, int offset)
{
return pointer + offset;
}
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
public static IntPtr Subtract(IntPtr pointer, int offset)
{
return pointer - offset;
}
[SecuritySafeCritical]
[CLSCompliant(false)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public unsafe void* ToPointer()
{
return this.m_value;
}
}
}
IntPtr是一种托管类型,用于获取Windows操作系统的本机句柄。您不应该将它与int*
这样的实际指针混淆。
请参阅MSDN以获取更多参考。
IntPtr
本质上只是指针类型的托管表示。您可以在不安全的上下文中自由地将任何指针类型强制转换为IntPtr
。从本质上讲,IntPtr
只是void*
的一个薄薄的包装(IIRC包含一个私有的void*
字段)。
它通常在与非托管代码的互操作过程中(通过PInvoke
或Marshal
类)作为非托管指针类型的就地替换,因为与指针一样,IntPtr
的大小随体系结构而变化(x86系统上为4字节,x64系统上为8字节)。
一个相关的问题。。。为什么dllimport不需要不安全的上下文?
我怀疑IntPtr和dllimport不需要不安全上下文的原因是为了使VB.NET(没有不安全的)能够轻松访问本机API。
然而,dllimport、IntPtr及其相互作用肯定存在"不安全"之处。
将无效参数交给dllimport入口点可能会导致崩溃,或者更糟的是,会悄悄损坏内存。这意味着在我看来,任何执行dllimport的代码都是"不安全的"。此外,如果该代码将IntPtr从安全代码泄漏到dllimport入口点,那么它本质上就是泄漏的——它"不安全"地泄漏到该安全代码中,因为安全代码可能会修改IntPtr使其无效。
当我使用dllimport时,我更喜欢将指针键入为不安全的结构指针,而不是IntPtr。这有两大好处。首先,它为我提供了不同类型的本机指针的类型检查。其次,它可以防止危险的非托管本机指针泄漏到"安全"代码中。
http://www.codeproject.com/script/Articles/ArticleVersion.aspx?aid=339290&av=638710
http://software.1713.n2.nabble.com/using-unsafe-struct-instead-of-IntPtr-with-PInvoke-td5861023.html