特にC#または.NETでポインター操作を実行する方法を探しています。
とても簡単なことをしたい
ポインターIntPtrがあると、2バイト先を指すIntPtrオブジェクトを取得できます。
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
計算を実行するには、ToInt64()とlongを使用することをお勧めします。このようにして、.NETフレームワークの64ビットバージョンでの問題を回避します。
IntPtr ptr = new IntPtr(oldptr.ToInt64() + 2);
これにより、32ビットシステムでオーバーヘッドが少し追加されますが、安全です。
.net 4では、静的なAdd()およびSubtract()メソッドが追加されました。
IntPtr ptr = IntPtr.Add(oldPtr, 2);
http://msdn.Microsoft.com/en-us/library/system.intptr.add.aspx
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
タイプは、ハンドルまたはポインターを渡すため、およびポインターをサポートする言語にマーシャリングするためのものです。しかし、それはポインター演算用ではありません。
Marshal.ReadByte()、Marshal.ReadInt16()などのメソッドを使用すると、ポインタ操作を回避できることがわかりました。このメソッドグループでは、IntPtr ...に関連してオフセットを指定できます。
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
}
拡張メソッドを使用できます。
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 );