Безопасное приведение IntPtr в C#

Вопрос

Какое приведение лучше всего подходит для 4-байтового IntPtr (строго для x84-приложения)

int : выглядит наиболее логичным приведением, но всегда ли оно безопасно на x84?

uint : Предположим, это сработает, если все указатели положительны? (Насколько я мог найти в моем случае)

long : Предположим, это также безопасно, за исключением случаев, когда вы создаете новый IntPtr с длинной на x84, возможно ли, что вы получите переполнение?

Предположим, у меня есть веская причина для приведения к одному из вышеуказанных типов, причина этого выходит за рамки этого вопроса.

Я просмотрел все вопросы о переполнении стека, которые смог найти, и просмотрел документацию MS, но боюсь, что недостаток знаний в этой области серьезно ограничивает мою способность найти ответ.


person Riaan Walters    schedule 06.08.2015    source источник


Ответы (2)


Существует метод IntPtr.ToInt64() или IntPtr.ToInt32(), который сделает это за вас. Имейте в виду, что IntPtr.ToInt32() вызывает OverflowException на 64-битной платформе, потому что экземпляр слишком велик или слишком мал для представления в виде 32-битного целого числа со знаком.

person CodeTherapist    schedule 06.08.2015
comment
+1. Я бы добавил, что ответ на вопрос кверента о том, что за исключением случаев, когда вы создаете новый IntPtr с длинной на x84 [так в оригинале], вы не можете получить переполнение? да, но только если IntPtr находится за пределами диапазона, который IntPtr будет иметь на x86, поэтому, если он возник из программы, у него не будет проблем. - person Jon Hanna; 06.08.2015
comment
Использование преобразования Int64 может привести к несоответствиям нативных API, что может привести к явному приведению типов для исправления предыдущего использования ToInt64. Дело немного сложнее, но поскольку OP запрашивает x86 и подписанный IntPtr, я бы поддержал его первый вариант, используя ToInt32. В случае, если его приложение когда-нибудь может быть преобразовано в x64 или AnyCPU, я бы включил вызов ToInt32 в статический метод вместе с проверкой отладки о том, что размер IntPtr составляет 32 бита. - person Rubidium 37; 06.08.2015
comment
IntPtr, о котором я прошу, действительно x86, но не подписан специально - person Riaan Walters; 06.08.2015

После некоторых дебатов с большинством коллег один из других старших разработчиков предложил мне написать оболочку и позволить среде решать, что ей нужно делать самой.

После тестирования при использовании Marshal.SizeOf(typeof(CPtr)) возвращалось

  • 4 on x84
  • 8 on x64

что именно так, как и ожидалось. но затем с дополнительным бонусом в том, что вам никогда не придется разыгрывать себя.

public struct CPtr
{
    public IntPtr InnerPointer { get; }
    public static IntPtr Zero { get { return IntPtr.Zero; } }

    public CPtr(IntPtr innerPointer)
    {
        InnerPointer = innerPointer;
    }
    public CPtr(long o) : this(new IntPtr(o))
    { }
    public CPtr(uint o) : this(new IntPtr(o))
    { }
    public CPtr(int o) : this(new IntPtr(o))
    { }


    public static CPtr operator +(CPtr a, long b)
    {
        return new CPtr((long)a.InnerPointer + b);
    }
    public static CPtr operator +(CPtr a, IntPtr b) { return a + (long)b; }
    public static CPtr operator +(CPtr a, CPtr b) { return a + b.InnerPointer; }
    public static CPtr operator +(CPtr a, uint b) { return a + (long)b; }
    public static CPtr operator +(CPtr a, int b) { return a + (long)b; }

    public static CPtr operator -(CPtr a, long b) { return a + -b; }
    public static CPtr operator -(CPtr a, IntPtr b) { return a + -(long)b; }
    public static CPtr operator -(CPtr a, CPtr b) { return a - b.InnerPointer; }
    public static CPtr operator -(CPtr a, uint b) { return a + -b; }
    public static CPtr operator -(CPtr a, int b) { return a + -b; }

    public static implicit operator CPtr(IntPtr ptr) { return new CPtr(ptr); }
    public static implicit operator CPtr(long ptr) { return new CPtr(ptr); }
    public static implicit operator CPtr(uint ptr) { return new CPtr(ptr); }
    public static implicit operator CPtr(int ptr) { return new CPtr(ptr); }


    public static implicit operator IntPtr(CPtr ptr) { return ptr.InnerPointer; }
    public static implicit operator long (CPtr ptr) { return (long)ptr.InnerPointer; }
    public static implicit operator uint (CPtr ptr) { return (uint)ptr.InnerPointer; }
    public static implicit operator int (CPtr ptr) { return (int)ptr.InnerPointer; }
}
person Riaan Walters    schedule 06.08.2015