简体   繁体   English

为什么IntPtr不需要unsafe关键字?

[英]Why doesn't IntPtr need the unsafe keyword?

When you use a pointer like int* in C#, you need to use the unsafe keyword, but when you use an IntPtr , you don't. 在C#中使用像int*这样的指针时,需要使用unsafe关键字,但是在使用IntPtr ,则不需要。 What is the difference of these? 这些有什么区别? They both can point to an address. 他们俩都可以指向一个地址。

How does the garbage collector deal with these two types? 垃圾收集器如何处理这两种类型? Are they dealt with differently? 他们的处理方式不同吗? If so, what is the difference? 如果是这样,有什么区别? If not, why one needs the unsafe keyword? 如果不是,为什么需要unsafe关键字?

Edit: Thanks a lot for everyone's answers so far, but what I would like to know is how they are handled differently by the framework and the garbage collector, rather than the MSDN definition of IntPtr . 编辑:到目前为止,非常感谢大家的回答,但是我想知道的是框架和垃圾收集器如何不同地处理它们,而不是IntPtr的MSDN定义。 It only takes one Google search to go there. 只需进行一次Google搜索即可。 What I'd like to know why IntPtr does not need the unsafe keyword? 我想知道为什么IntPtr不需要unsafe关键字? I would like to grasp the reason why we can use it without the keyword. 我想了解没有关键字就可以使用它的原因。

According to MSDN: 根据MSDN:

http://msdn.microsoft.com/en-gb/library/system.intptr(v=vs.100).aspx http://msdn.microsoft.com/zh-CN/library/system.intptr(v=vs.100).aspx

It is merely a representation of "a pointer or a handle." 它仅是“指针或句柄”的表示

I have been doing some reading on how the IntPtr is handled differently by the GC than other managed types, and I have not found any documentation or articles stating the IntPtr is collected any differently, ie, as soon as the IntPtr goes out of scope it can be GC'd. 我一直在阅读有关GC与其他托管类型如何不同地处理IntPtr ,并且我还没有发现任何说明IntPtr的收集方式有所不同的文档或文章,即,一旦IntPtr超出范围,它可以被GC。

About why there is no use of the unsafe keyword read the accepted answer especially the update: 关于为什么不使用unsafe关键字的原因,请阅读已接受的答案,尤其是更新内容:

Does unsafe code have any effect on safe code? 不安全代码对安全代码有影响吗?

unsafe has already been specified in the implementation of IntPtr (see the field declarations in the IntPtr implementation below), so the class using the IntPtr does not have to mark any use of IntPtr it uses as unsafe also, otherwise it would be cascaded all the way up to other classes that might use types that have unsafe code in their implementation. unsafe已经在执行指定IntPtr (见域声明IntPtr下面实现),因此,使用类IntPtr没有标记任何使用IntPtr它使用的unsafe也,否则会级联所有到其他可能在实现中使用不安全代码的类的类。

Besides the unsafe code is not IntPtr , it is the field private unsafe void* m_value; 除了unsafe代码不是IntPtr ,它是字段private unsafe void* m_value; that is unsafe and you are not using it directly. 这是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 is a managed type and is used , ie to get native handles of the Windows OS. IntPtr是一种托管类型,用于,即获取Windows OS的本机句柄。 You shouldn't confuse it with an actual pointer like int* . 您不应将其与int*这样的实际指针混淆。

See MSDN for further reference. 有关更多参考,请参见MSDN

An IntPtr is essentially just a managed representation of a pointer type. IntPtr本质上只是指针类型的托管表示形式。 You can freely cast any pointer types to an IntPtr in an unsafe context. 您可以在不安全的上下文中将任何指针类型自由转换为IntPtr Essentially an IntPtr is just a thin wrapper around a void* (IIRC it contains a private void* field). 本质上, IntPtr只是围绕void* (IIRC它包含一个私有void*字段)的薄包装。

It's commonly during interop with unmanaged code (via PInvoke or the Marshal class) as an in-place replacement for unmanaged pointer types as, like pointers, an IntPtr 's size varies with architecture (4 bytes on a x86 system, 8 on a x64). 通常在与非托管代码(通过PInvokeMarshal类)进行互操作期间作为非托管指针类型的就地替换,因为就像指针一样, IntPtr的大小随体系结构而有所不同(x86系统上为4个字节,x64系统上为8个字节) )。

A related question... Why doesn't dllimport require an unsafe context? 一个相关问题...为什么dllimport不需要不安全的上下文?

I suspect the reason IntPtr and dllimport do not require an unsafe context is to enable VB.NET (which doesn't have unsafe) to access native APIs easily. 我怀疑IntPtr和dllimport不需要不安全上下文的原因是使VB.NET(没有不安全)可以轻松访问本机API。

However, there is certainly something "unsafe" about dllimport, IntPtr and their interaction. 但是,对于dllimport,IntPtr及其交互,肯定存在某些“不安全”之处。

Handing invalid arguments to a dllimport entry-point can cause a crash, or worse, silently corrupt memory. 将无效的参数传递给dllimport入口点可能会导致崩溃,或更糟糕的是,无提示地破坏内存。 This means any code which does a dllimport is in my mind "unsafe". 这意味着在我看来,任何执行dllimport的代码都是“不安全的”。 Further, if that code leaks an IntPtr from safe code into the dllimport entry point, it's essentially leaked it's "unsafety" out into that safe code, because the safe code could modify the IntPtr to make it invalid. 此外,如果该代码将IntPtr从安全代码泄漏到dllimport入口点,则实质上是在安全代码中泄漏了“不安全”,因为安全代码可以修改IntPtr使其无效。

When I use dllimport, I prefer to type pointers as unsafe-struct pointers, rather than IntPtr. 当我使用dllimport时,我更喜欢将指针键入为unsafe-struct指针,而不是IntPtr。 This has two big benefits. 这有两个好处。 First, it gives me type-checking for different types of native pointers. 首先,它使我可以检查不同类型的本机指针的类型。 Second, it prevents dangerous unmanaged native pointers from leaking out into "safe" code. 其次,它可以防止危险的非托管本机指针泄漏到“安全”代码中。

http://www.codeproject.com/script/Articles/ArticleVersion.aspx?aid=339290&av=638710 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 http://software.1713.n2.nabble.com/using-unsafe-struct-instead-of-IntPtr-with-PInvoke-td5861023.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM