Что такое IntPtr?


171

Используя IntelliSense и просматривая чужой код, я столкнулся с этим IntPtrтипом; каждый раз, когда это нужно было использовать, я просто помещал nullили IntPtr.Zeroнаходил большинство функций для работы. Что именно и когда / почему он используется?

Ответы:


158

Это «родное (зависящее от платформы) целое число размера». Это внутренне представлено как, void*но выставлено как целое число. Вы можете использовать его всякий раз, когда вам нужно сохранить неуправляемый указатель и не хотите использовать unsafeкод. IntPtr.Zeroэффективно NULL(нулевой указатель).


53
Указатель - это то, что указывает на адрес в памяти. На управляемых языках у вас есть ссылки (адрес может перемещаться), в то время как на неуправляемых языках у вас есть указатели (адрес фиксирован)
Колин Маккей

93
В целом (для разных языков программирования) указатель - это число, представляющее физическое расположение в памяти. Нулевой указатель (почти всегда) один , что указывает на 0, и широко признан как «не указывает на что - нибудь». Поскольку системы имеют различное количество поддерживаемой памяти, для хранения этого числа не всегда требуется одинаковое количество байтов, поэтому мы называем «целое число собственного размера», которое может содержать указатель на любую конкретную систему.
Сэм Харвелл

5
+1 за этот комментарий @ 280Z28, это самое краткое объяснение указателей, которые я когда-либо видел.
BlueRaja - Дэнни Пфлюгофт

9
Он называется IntPtr, потому что для его использования из неуправляемого нативного кода C / C ++ вам придется использовать аналогичный тип: intptr_t. IntPtr в C # точно соответствует intptr_t в C / C ++. И это, вероятно, реализовано как intptr_t. В C / C ++ тип intptr_t гарантированно будет того же размера, что и тип void *.
Петър Петров

2
@Trap "Тип платформы, который используется для представления указателя или дескриптора." Не «платформо-целое число», а «платформенный способ представления указателя или дескриптора». IntPtrимеет смысл, потому что это целое число (как в математическом целом) и указатель (как в указателе). IntЧасть имеет мало общего с типом Int - это понятие, а не тип специфичны. Хотя, чтобы быть справедливым, единственное, что спецификация CLI говорит об этом, - это то, что это действительно "Integer, native size". Ну да ладно :)
Luaan

69

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

Вы можете использовать, IntPtr.Sizeчтобы узнать, используете ли вы 32-битный или 64-битный процесс, так как он будет 4 или 8 байтов соответственно.


16
Хорошая мысль об определении размера адресного пространства для процесса.
Нолдорин

@Noldorin Верно, но не обязательно надежно. В прошлом было много архитектур с несколькими типами указателей, а в Windows IntPtrтакже использовались 32-битные дескрипторы для представления дескрипторов независимо от архитектуры (хотя Sizeв этом случае все равно указано 8). В спецификации CLI только отмечается, что это целое число «родного размера», но на самом деле это мало что говорит.
Луаан

@ Луа, это ничего не меняет в моем ответе, не так ли? IntPtr называется (и используется во всем источнике CLR) как значение, достаточно большое для хранения адреса памяти. Конечно, он может содержать меньшие значения. Некоторые архитектуры имеют несколько типов указателей, но должны иметь самый большой из множества.
Дэниел Уорвикер

@ DanielEarwicker Ну, насколько я знаю, это не проблема для любой текущей реализации .NET. Однако (историческая) проблема связана не только с размером - различные указатели могут быть совершенно несовместимы. В примере, близком к сегодняшнему, PAE будет использовать 64-битные адреса, даже если «размер собственного указателя» все еще будет 32-битным. Все идет обратно к аргументу "что на самом деле означает" 32-битная система "?" Сейчас у нас есть 256-битные и 512-битные числовые регистры, но мы все еще называем их 64-битными. Даже если вы не можете адресовать 64-битную физическую память своими 64-битными «указателями». Это беспорядок.
Луан

1
Некоторые из них сложные, но IntPtr по-прежнему «тип значения, достаточно большой для хранения адреса памяти». Он не такой большой, как самый большой аппаратный регистр, чтобы взять один из ваших примеров. Это просто не то, для чего это. Он достаточно большой, чтобы представлять адрес памяти. Тогда есть такие вещи: stackoverflow.com/questions/12006854/… где у нас есть слово «указатель», используемое для чего-то, кроме адреса памяти - именно поэтому я специально сказал «адрес памяти».
Дэниел Эрвикер

48

Вот пример:

Я пишу программу на C #, которая взаимодействует с высокоскоростной камерой. У камеры есть собственный драйвер, который автоматически получает изображения и загружает их в память компьютера.

Поэтому, когда я готов перенести последнее изображение в мою программу для работы, драйвер камеры предоставляет мне IntPtr для того, где изображение УЖЕ хранится в физической памяти, поэтому мне не нужно тратить время / ресурсы на создание другого блок памяти для хранения изображения, которое уже находится в памяти. IntPtr просто показывает мне, где изображение уже есть.


7
Таким образом, IntPtr simple позволяет вам использовать неуправляемый указатель (например, используемый в драйвере камеры) в управляемом коде?
Каллум Роджерс

5
Да. В этом случае, скорее всего, драйвер камеры использует неуправляемые драйверы под капотом, но для правильной работы в мире, управляемом только, он предоставляет IntPtr, позволяющий мне безопасно работать с данными.
bufferz

3
Так почему бы просто не вернуть вам поток (байтовый массив)? Почему это небезопасно или невозможно вернуть значение?
Маффин Человек

35

Прямая интерпретация

IntPtr представляет собой целое число , которое имеет такой же размер , как указатель .

Вы можете использовать IntPtr для хранения значения указателя в типе без указателя. Эта функция важна в .NET, так как использование указателей очень подвержено ошибкам и, следовательно, недопустимо в большинстве случаев. Позволяя сохранить значение указателя в «безопасном» типе данных, прокладка между небезопасными сегментами кода может быть реализована в более безопасном высокоуровневом коде - или даже в языке .NET, который напрямую не поддерживает указатели.

Размер IntPtr зависит от платформы, но эту деталь редко нужно учитывать, поскольку система автоматически использует правильный размер.

Название «IntPtr» сбивает с толку - что-то вроде Handleмогло бы быть более подходящим. Первоначально я предполагал, что IntPtr - это указатель на целое число. Документации MSDN из IntPtr переходит в несколько скрытом подробно никогда не обеспечивая намного больше информации о значении имени.

Альтернативная перспектива

Это IntPtrуказатель с двумя ограничениями:

  1. Это не может быть напрямую разыменовано
  2. Он не знает тип данных, на которые он указывает.

Другими словами, an IntPtrпохож на a void*- но с дополнительной функцией, которую он может (но не должен) использовать для базовой арифметики указателей.

Чтобы разыменовать an IntPtr, вы можете либо привести его к истинному указателю (операция, которая может быть выполнена только в «небезопасных» контекстах), либо вы можете передать его вспомогательной подпрограмме, например, предоставляемой InteropServices.Marshalклассом. Использование Marshalкласса дает иллюзию безопасности, поскольку он не требует от вас явного «небезопасного» контекста. Однако это не устраняет риск сбоя, который присущ указателям.


2
Существует некоторый прецедент для имени "intptr" из стандарта C99 языка программирования "C". linux.die.net/man/3/intptr_t .
Брент Брэдберн

17

Что такое указатель?

Во всех языках указатель - это тип переменной, в которой хранится адрес памяти, и вы можете либо попросить их сообщить вам адрес, на который они указывают, либо значение по адресу, на который они указывают.

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

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

Указатели послушно указывают

Указатели запоминают один адрес памяти каждый, и поэтому каждый из них указывает на один адрес в памяти.

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

Вы их король.

Указатели в C #

В частности, в C # указатель является целочисленной переменной, которая хранит адрес памяти от 0 до 65534.

Также характерные для C #, указатели имеют тип int и поэтому подписаны.

Вы не можете использовать адреса с отрицательной нумерацией, а также не можете получить доступ к адресу выше 65534. Любая попытка сделать это вызовет исключение System.AccessViolationException.

Указатель MyPointer объявлен так:

int * MyPointer;

Указатель в C # - это int, но адреса памяти в C # начинаются с 0 и простираются до 65534.

Остроконечные вещи должны обрабатываться с особой тщательностью

Слово небезопасно это предназначено , чтобы напугать вас, так и для очень веских причин: Указатели заостренных вещи, и заостренных вещи , например , мечи, топоры, указатели и т.д. , должны быть обработан с дополнительной особой тщательности.

Указатели дают программисту жесткий контроль над системой. Поэтому допущенные ошибки могут иметь более серьезные последствия.

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

Пример небезопасного блока

unsafe
{
    // Place code carefully and responsibly here.

}

Как использовать указатели

Когда переменные или объекты объявляются или создаются, они сохраняются в памяти.

  • Объявите указатель с помощью префикса символа *.

int *MyPointer;

  • Чтобы получить адрес переменной, вы используете префикс & symbol.

MyPointer = &MyVariable;

Как только адрес назначен указателю, применяется следующее:

  • Без префикса * для обозначения адреса памяти, на который указывает int.

MyPointer = &MyVariable; // Set MyPointer to point at MyVariable

  • С префиксом *, чтобы получить значение, сохраненное по адресу памяти, на который указывает.

"MyPointer is pointing at " + *MyPointer;

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

Пример использования указателей аккуратно и ответственно

    public unsafe void PointerTest()
    {
        int x = 100; // Create a variable named x

        int *MyPointer = &x; // Store the address of variable named x into the pointer named MyPointer

        textBox1.Text = ((int)MyPointer).ToString(); // Displays the memory address stored in pointer named MyPointer

        textBox2.Text = (*MyPointer).ToString(); // Displays the value of the variable named x via the pointer named MyPointer.

    }

Обратите внимание, что тип указателя - int. Это потому, что C # интерпретирует адреса памяти как целые числа (int).

Почему это int вместо uint?

Нет веской причины.

Зачем использовать указатели?

Указатели очень весело. Так как большая часть компьютера управляется памятью, указатели дают программисту больше контроля над памятью их программ.

Мониторинг памяти.

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

Измените эти значения ответственно и следите за тем, как ваши изменения влияют на ваш компьютер.


2
65534кажется очень неправильным в качестве указателя диапазона. Вы должны предоставить ссылку.
Брент Брэдберн

1
Я проголосовал за это, потому что это отличная статья с пояснениями. Я хотел бы видеть некоторые ссылки на спецификации, которые вы упомянули (как прокомментировано выше). Тем не мение; этот ответ не имеет ничего общего с вопросом. Вопрос был о System.IntPtr. Я хотел бы видеть обновленный ответ в конце, объясняющий, что также System.IntPtrи как это относится к небезопасным указателям в C #, пожалуйста.
Майкл Пакетт II

7

MSDN говорит нам:

Тип IntPtr предназначен для целого числа, размер которого зависит от платформы. Таким образом, ожидается, что экземпляр этого типа будет 32-разрядным в 32-разрядных аппаратных и операционных системах и 64-разрядным в 64-разрядных аппаратных и операционных системах.

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

Объекты IntPtr также можно использовать для хранения дескрипторов. Например, экземпляры IntPtr широко используются в классе System.IO.FileStream для хранения файловых дескрипторов.

Тип IntPtr совместим с CLS, а тип UIntPtr - нет. В общеязыковой среде выполнения используется только тип IntPtr. Тип UIntPtr предоставляется в основном для поддержания архитектурной симметрии с типом IntPtr.

http://msdn.microsoft.com/en-us/library/system.intptr(VS.71).aspx


5

Ну, это страница MSDN, которая имеет дело с IntPtr.

Первая строка гласит:

Специфичный для платформы тип, который используется для представления указателя или дескриптора.

Что касается указателя или дескриптора, то страница переходит в состояние:

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

Объекты IntPtr также можно использовать для хранения дескрипторов. Например, экземпляры IntPtr широко используются в классе System.IO.FileStream для хранения файловых дескрипторов.

Указатель - это ссылка на область памяти, которая содержит некоторые данные, которые вас интересуют.

Дескриптор может быть идентификатором объекта и передается между методами / классами, когда обеим сторонам необходим доступ к этому объекту.


2

An IntPtrявляется типом значения, который в основном используется для хранения адресов или дескрипторов памяти. Указатель является адресом памяти. Указатель может быть напечатан (например int*) или нетипизирован (например void*). Дескриптор Windows - это значение, которое обычно имеет тот же размер (или меньше), что и адрес памяти, и представляет системный ресурс (например, файл или окно).

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.