2009-12-08 73 views
31

我正在尋找一種方法來在C#或.NET中執行指針操作。將偏移量添加到IntPtr

我想要做的東西很簡單

有一個指針的IntPtr我想要得到的IntPtr對象指向未來2個字節。

我看了一些帖子說的foolowing片段將工作...

IntPtr ptr = new IntPtr(oldptr.ToInt32() + 2); 

但我懷疑這種說法是否也適用於64位機(因爲尋址是在64位有)。 。

我發現這個優雅的方法來添加偏移,但不幸的是,在.NET 4.0中只有http://msdn.microsoft.com/en-us/library/system.intptr.add%28VS.100%29.aspx

+0

字節仍然是一個64位機器上的一個字節。所以,它仍然會跳過兩個字節。 – 2009-12-08 11:07:26

+1

@dan:是的,但是該字節的地址可以在32位範圍之外! Marcin對於64位無效是正確的。 – Lucero 2009-12-08 12:09:13

回答

33

我建議你使用ToInt64()和長來執行你的計算。這樣你就可以避免在.NET框架的64位版本上出現問題。

IntPtr ptr = new IntPtr(oldptr.ToInt64() + 2); 

這增加了32位系統的開銷,但它更安全。

1

您可以使用擴展方法:

public static IntPtrExtensions { 
    public static IntPtr Add(this IntPtr ptr, int offSet) { 
     IntPtr ret = new IntPtr(ptr.ToInt64() + offSet); 
     return ret; 
    } 
} 
// ... somewhere else ... 
IntPtr pointer = GetHandle().Add(15); 
9

對於指針運算在C#中,你應該使用一個unsafe的上下文內部的正常指針:

class PointerArithmetic 
{ 
    unsafe static void Main() 
    { 
     int* memory = stackalloc int[30]; 
     long* difference; 
     int* p1 = &memory[4]; 
     int* p2 = &memory[10]; 

     difference = (long*)(p2 - p1); 

     System.Console.WriteLine("The difference is: {0}", (long)difference); 
    } 
} 

IntPtr類型是繞過處理或指針也用於編組支持指針的語言。但它不適用於指針算術。

+1

用於實數指針算術,而不是濫用整數ALU來執行地址計算。 – Frank 2010-04-24 18:02:46

+5

現在.NET 4中的Microsoft已經引入了IntPtr.Add,它返回「一個新的指針,它反映了偏移量添加到指針」,這使得IntPtr便於指針算術,並且似乎表明Microsoft期望它被用於。 – Spike0xff 2013-12-31 19:44:13

8

我發現我可以通過使用Marshal.ReadByte(),Marshal.ReadInt16()等方法來避免指針操作。這組方法允許指定相對於IntPtr的偏移...

4
public static class IntPtrExtensions 
{ 
    #region Methods: Arithmetics 
    public static IntPtr Decrement(this IntPtr pointer, Int32 value) 
    { 
     return Increment(pointer, -value); 
    } 

    public static IntPtr Decrement(this IntPtr pointer, Int64 value) 
    { 
     return Increment(pointer, -value); 
    } 

    public static IntPtr Decrement(this IntPtr pointer, IntPtr value) 
    { 
     switch (IntPtr.Size) 
     { 
      case sizeof(Int32): 
       return (new IntPtr(pointer.ToInt32() - value.ToInt32())); 

      default: 
       return (new IntPtr(pointer.ToInt64() - value.ToInt64())); 
     } 
    } 

    public static IntPtr Increment(this IntPtr pointer, Int32 value) 
    { 
     unchecked 
     { 
      switch (IntPtr.Size) 
      { 
       case sizeof(Int32): 
        return (new IntPtr(pointer.ToInt32() + value)); 

       default: 
        return (new IntPtr(pointer.ToInt64() + value)); 
      } 
     } 
    } 

    public static IntPtr Increment(this IntPtr pointer, Int64 value) 
    { 
     unchecked 
     { 
      switch (IntPtr.Size) 
      { 
       case sizeof(Int32): 
        return (new IntPtr((Int32)(pointer.ToInt32() + value))); 

       default: 
        return (new IntPtr(pointer.ToInt64() + value)); 
      } 
     } 
    } 

    public static IntPtr Increment(this IntPtr pointer, IntPtr value) 
    { 
     unchecked 
     { 
      switch (IntPtr.Size) 
      { 
       case sizeof(int): 
        return new IntPtr(pointer.ToInt32() + value.ToInt32()); 
       default: 
        return new IntPtr(pointer.ToInt64() + value.ToInt64()); 
      } 
     } 
    } 
    #endregion 

    #region Methods: Comparison 
    public static Int32 CompareTo(this IntPtr left, Int32 right) 
    { 
     return left.CompareTo((UInt32)right); 
    } 

    public static Int32 CompareTo(this IntPtr left, IntPtr right) 
    { 
     if (left.ToUInt64() > right.ToUInt64()) 
      return 1; 

     if (left.ToUInt64() < right.ToUInt64()) 
      return -1; 

     return 0; 
    } 

    public static Int32 CompareTo(this IntPtr left, UInt32 right) 
    { 
     if (left.ToUInt64() > right) 
      return 1; 

     if (left.ToUInt64() < right) 
      return -1; 

     return 0; 
    } 
    #endregion 

    #region Methods: Conversion 
    public unsafe static UInt32 ToUInt32(this IntPtr pointer) 
    { 
     return (UInt32)((void*)pointer); 
    } 

    public unsafe static UInt64 ToUInt64(this IntPtr pointer) 
    { 
     return (UInt64)((void*)pointer); 
    } 
    #endregion 

    #region Methods: Equality 
    public static Boolean Equals(this IntPtr pointer, Int32 value) 
    { 
     return (pointer.ToInt32() == value); 
    } 

    public static Boolean Equals(this IntPtr pointer, Int64 value) 
    { 
     return (pointer.ToInt64() == value); 
    } 

    public static Boolean Equals(this IntPtr left, IntPtr ptr2) 
    { 
     return (left == ptr2); 
    } 

    public static Boolean Equals(this IntPtr pointer, UInt32 value) 
    { 
     return (pointer.ToUInt32() == value); 
    } 

    public static Boolean Equals(this IntPtr pointer, UInt64 value) 
    { 
     return (pointer.ToUInt64() == value); 
    } 

    public static Boolean GreaterThanOrEqualTo(this IntPtr left, IntPtr right) 
    { 
     return (left.CompareTo(right) >= 0); 
    } 

    public static Boolean LessThanOrEqualTo(this IntPtr left, IntPtr right) 
    { 
     return (left.CompareTo(right) <= 0); 
    } 
    #endregion 

    #region Methods: Logic 
    public static IntPtr And(this IntPtr pointer, IntPtr value) 
    { 
     switch (IntPtr.Size) 
     { 
      case sizeof(Int32): 
       return (new IntPtr(pointer.ToInt32() & value.ToInt32())); 

      default: 
       return (new IntPtr(pointer.ToInt64() & value.ToInt64())); 
     } 
    } 

    public static IntPtr Not(this IntPtr pointer) 
    { 
     switch (IntPtr.Size) 
     { 
      case sizeof(Int32): 
       return (new IntPtr(~pointer.ToInt32())); 

      default: 
       return (new IntPtr(~pointer.ToInt64())); 
     } 
    } 

    public static IntPtr Or(this IntPtr pointer, IntPtr value) 
    { 
     switch (IntPtr.Size) 
     { 
      case sizeof(Int32): 
       return (new IntPtr(pointer.ToInt32() | value.ToInt32())); 

      default: 
       return (new IntPtr(pointer.ToInt64() | value.ToInt64())); 
     } 
    } 

    public static IntPtr Xor(this IntPtr pointer, IntPtr value) 
    { 
     switch (IntPtr.Size) 
     { 
      case sizeof(Int32): 
       return (new IntPtr(pointer.ToInt32()^value.ToInt32())); 

      default: 
       return (new IntPtr(pointer.ToInt64()^value.ToInt64())); 
     } 
    } 
    #endregion 
} 
+1

這不是最好的答案......也許增加了一些評論,但代碼本身就說明了... – DeeJayh 2017-10-09 05:20:54