简体   繁体   English

向 IntPtr 添加偏移量

[英]Add offset to IntPtr

I'm looking for a way to perform pointer operations in C# or .NET in particular.我正在寻找一种特别是在 C# 或 .NET 中执行指针操作的方法。

I want to do something very simple我想做一些非常简单的事情

Having a pointer IntPtr I want to get IntPtr object which points to 2 bytes ahead.有一个指针 IntPtr 我想获得指向前面 2 个字节的 IntPtr 对象。

I read some post that the foolowing snippet will work...我读了一些帖子说愚蠢的片段会起作用......

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

But I have doubts whether this statement is also valid for 64-bit machine (since addressing is in 64-bits there)..但是我怀疑这个语句是否也适用于 64 位机器(因为寻址是在 64 位那里)..

I found this elegant method to add offset, but unfortunately is in .NET 4.0 only http://msdn.microsoft.com/en-us/library/system.intptr.add%28VS.100%29.aspx我发现了这种添加偏移量的优雅方法,但不幸的是仅在 .NET 4.0 中http://msdn.microsoft.com/en-us/library/system.intptr.add%28VS.100%29.aspx

In .net 4 static Add() and Subtract() methods have been added.在 .net 中添加了 4 个静态 Add() 和 Subtract() 方法。

IntPtr ptr = IntPtr.Add(oldPtr, 2);

http://msdn.microsoft.com/en-us/library/system.intptr.add.aspx http://msdn.microsoft.com/en-us/library/system.intptr.add.aspx

I suggest you to use ToInt64() and long to perform your computation.我建议您使用 ToInt64() 和 long 来执行计算。 This way you will avoid problem on 64 bits version of the .NET framework.这样您就可以避免 64 位版本的 .NET 框架出现问题。

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

This add a bit of overhead on 32 bits system, but it is safer.这在 32 位系统上增加了一点开销,但它更安全。

For pointer arithmetic in C# you should use proper pointers inside an unsafe context:对于 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);
    }
}

The IntPtr type is for passing around handles or pointers and also for marshalling to languages that support pointers. IntPtr类型用于传递句柄或指针,也用于编组到支持指针的语言。 But it's not for pointer arithmetic.但这不适用于指针算术。

I found that I can avoid pointer operations by using Marshal.ReadByte(), Marshal.ReadInt16() etc. methods.我发现我可以通过使用 Marshal.ReadByte()、Marshal.ReadInt16() 等方法来避免指针操作。 This group of methods allow to specify offset in releation to the IntPtr...这组方法允许指定与 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
}

You can use a extension method:您可以使用扩展方法:

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 );

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

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