c# - Aggiungi offset a IntPtr



.net pinvoke interop (6)

Sto cercando un modo per eseguire operazioni di puntatore in C # o .NET in particolare.

Voglio fare qualcosa di molto semplice

Avere un puntatore IntPtr Voglio ottenere l'oggetto IntPtr che punta a 2 byte avanti.

Ho letto alcuni post che lo snippet ingannevole funzionerà ...

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

Ma dubito che questa affermazione sia valida anche per macchine a 64-bit (dato che l'indirizzamento è a 64-bit lì) ..

Ho trovato questo elegante metodo per aggiungere offset, ma sfortunatamente è in .NET 4.0 solo http://msdn.microsoft.com/en-us/library/system.intptr.add%28VS.100%29.aspx


Answers

Ti suggerisco di usare ToInt64 () e a lungo per eseguire il tuo calcolo. In questo modo si eviterà il problema nella versione a 64 bit del framework .NET.

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

Questo aggiunge un po 'di overhead al sistema a 32 bit, ma è più sicuro.


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
}

Ho scoperto che posso evitare le operazioni del puntatore utilizzando i metodi Marshal.ReadByte (), Marshal.ReadInt16 () ecc. Questo gruppo di metodi consente di specificare l'offset in releation all'IntrPtr ...


Puoi utilizzare un metodo di estensione:

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

Per l'aritmetica del puntatore in C # dovresti usare i puntatori appropriati all'interno di un contesto 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);
    }
}

Il tipo IntPtr è per il passaggio di handle o puntatori e anche per il marshalling in lingue che supportano i puntatori. Ma non è per aritmetica puntatore.


Più semplice, usando l'interpolazione della stringa invece di String.Format

 $"{12456:n0}"; // 12,456
 $"{12456:n2}"; // 12,456.00

o usando la tua variabile

 double yourVariable = 12456.0;
 $"{yourVariable:n0}"; 
 $"{yourVariable:n2}"; 




c# .net pinvoke interop