向 IntPtr 添加偏移量

Posted

技术标签:

【中文标题】向 IntPtr 添加偏移量【英文标题】:Add offset to IntPtr 【发布时间】:2009-12-08 11:02:11 【问题描述】:

我正在寻找一种特别是在 C# 或 .NET 中执行指针操作的方法。

我想做一些非常简单的事情

有一个指针 IntPtr 我想获得指向前面 2 个字节的 IntPtr 对象。

我读过一些帖子说愚蠢的 sn-p 会起作用......

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

【问题讨论】:

一个字节在 64 位机器上仍然是一个字节。所以,它仍然会向前跳过两个字节。 @dan:是的,但是字节的地址可以在 32 位范围之外! Marcin 是正确的,这对 64 位无效。 【参考方案1】:

在 .net 中添加了 4 个静态 Add() 和 Subtract() 方法。

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

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

【讨论】:

为什么这是静态的。抱歉,我刚刚破坏了你的 1000 分的满分,为这个答案投了赞成票;/【参考方案2】:

我建议您使用 ToInt64() 和 long 来执行您的计算。这样可以避免 .NET 框架的 64 位版本出现问题。

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

这在 32 位系统上增加了一点开销,但更安全。

【讨论】:

【参考方案3】:

对于 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 来执行地址计算。 现在微软在 .NET 4 中引入了 IntPtr.Add ,它返回“一个新的指针,它反映了对指针的偏移量的添加”,这使得 IntPtr 便于指针算术,并且似乎表明微软期望它被用于那个。 使用不安全代码是有限制的——因此在编译期间需要 /unsafe 标志。如果可能的话,最好避免它。另外值得注意的是,无论您使用哪种方法,ALU 都用于计算地址。我看不出它是如何通过手动计算被“滥用”的。【参考方案4】:

我发现我可以通过使用 Marshal.ReadByte()、Marshal.ReadInt16() 等方法来避免指针操作。这组方法允许指定与 IntPtr 相关的偏移量...

【讨论】:

【参考方案5】:
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

【讨论】:

这不是最佳答案...也许添加一些评论,但代码不言自明...【参考方案6】:

您可以使用扩展方法:

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

【讨论】:

以上是关于向 IntPtr 添加偏移量的主要内容,如果未能解决你的问题,请参考以下文章

向内存地址添加偏移量

SwiftUI 向视图添加 -y 偏移量,但将视图拉伸到底部

pandas使用pd.DateOffset生成时间偏移量(指定年数月数天数小时分钟)把dataframe数据中的时间数据列统一偏移(相加偏移向后移动时间时间增加)

pandas使用pd.DateOffset生成时间偏移量(指定年数月数天数小时分钟)把dataframe数据中的时间数据列统一偏移(相加偏移向后移动时间时间增加)

pandas使用pd.DateOffset生成时间偏移量把dataframe数据中的时间数据列统一相加N天放大向后偏移N天

计算十六进制偏移量