Що саме таке IntPtr?


171

Завдяки використанню IntelliSense та перегляду коду інших людей я натрапив на цей IntPtrтип; кожного разу, коли це потрібно було використовувати, я просто ставив nullабо IntPtr.Zeroзнаходив більшість функцій для роботи. Що це саме і коли / для чого використовується?

Відповіді:


158

Це ціле ціле "нативного (для платформи)". Він внутрішньо представлений як void*цілий, але відкритий як ціле число. Ви можете використовувати його, коли потрібно зберігати некерований вказівник і не хочете використовувати unsafeкод. IntPtr.Zeroефективно NULL(нульовий покажчик).


53
Вказівник - це те, що вказує на адресу в пам'яті. У керованих мовах у вас є посилання (адреса може пересуватися), тоді як у некерованих мовах у вас є вказівники (адреса виправлена)
Колін Макей

93
Загалом (для різних мов програмування) вказівник - це число, яке представляє фізичне місце в пам'яті. Нульовий покажчик (майже завжди) один , що вказує на 0, і широко визнаний як «не вказує на що - небудь». Оскільки системи мають різну кількість підтримуваної пам’яті, вона не завжди займає однакову кількість байтів, щоб утримувати це число, тому ми називаємо «цілий цілий розмір», який може містити вказівник на будь-якій конкретній системі.
Сем Харвелл

5
+1 за коментар @ 280Z28, це найкоротше пояснення покажчиків, які я коли-небудь бачив.
BlueRaja - Danny Pflughoeft

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, це те, що це дійсно "цілий, рідний розмір". О добре :)
Луань

69

Це тип значення, достатньо великий, щоб зберігати адресу пам’яті, як вона використовується в рідному або небезпечному коді, але не може бути безпосередньо використана як адреса пам’яті в безпечному керованому коді.

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


16
Хороший момент щодо визначення розміру адресного простору для процесу.
Нолдорін

@Noldorin Правда, але не обов'язково надійна. У минулому було багато архітектур, які мали кілька типів вказівників, а в Windows IntPtrтакож використовується для представлення ручок, які є 32-бітними незалежно від архітектури (хоча Sizeвсе ще йдеться про 8 у цьому випадку). Специфікація CLI лише зазначає, що це ціле число "рідного розміру", але це не дуже говорить.
Луань

@Luaan, що насправді нічого не змінює в моїй відповіді? 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 дозволяє вам використовувати некерований покажчик (наприклад, який використовується у драйвері камери) в керованому коді?
Callum Rogers

5
Так. Добре, що в цьому випадку, швидше за все, драйвер камери використовує керовані драйвери під кришкою, але для правильної роботи в світі, керованому лише він, він надає IntPtr, що дозволяє мені безпечно працювати з даними.
bufferz

3
То чому б він просто не повернув вам потік (байтовий масив)? Чому це небезпечно чи не може повернути значення?
Людина-булочка

35

Пряме тлумачення

IntPtr є ціле число , яке має такий же розмір , як покажчик .

Ви можете використовувати IntPtr для зберігання значення вказівника у не-покажчиковому типі. Ця функція важлива у .NET, оскільки використання покажчиків дуже схильна до помилок і тому є незаконною у більшості контекстів. Дозволяючи зберігати значення вказівника у "безпечному" типі даних, сантехніка між небезпечними сегментами коду може бути реалізована у безпечнішому коді високого рівня - або навіть у .NET-мові, яка безпосередньо не підтримує покажчики.

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

Назва "IntPtr" є заплутаною - щось подібне, Handleможливо, було б більш доречним. Моя початкова здогадка полягала в тому, що "IntPtr" - вказівник на ціле число. Документація MSDN про IntPtr входить в дещо криптовалюту, ніколи не надаючи особливого розуміння значення цього імені.

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

An IntPtr- покажчик з двома обмеженнями:

  1. Це не може бути безпосередньо відмежоване
  2. Він не знає тип даних, на які він вказує.

Іншими словами, ан IntPtr- це просто як void*- але з додатковою функцією, яку він може (але не повинен) використовувати для основної арифметики вказівника.

Для того, щоб знешкодити IntPtr, ви можете передати його на справжній покажчик (операція, яка може бути виконана лише в "небезпечних" контекстах), або ви можете передати його в допоміжну процедуру, таку, яку надає InteropServices.Marshalклас. Використання Marshalкласу дає ілюзію безпеки, оскільки він не вимагає від вас явного «небезпечного» контексту. Однак це не знімає ризик збоїв, притаманний використанню покажчиків.


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

17

Що таке покажчик?

У всіх мовах вказівник - це тип змінної, яка зберігає адресу пам'яті, і ви можете або попросити їх повідомити вам адресу, на яку вони вказують, або значення за адресою, на яку вони вказують.

Вказівник можна розглядати як своєрідний знак книги. За винятком того, що замість того, щоб швидко переходити на сторінку в книзі, використовується вказівник для відстеження або картування блоків пам'яті.

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

Покажчики слухняно вказують

Покажчики пам’ятають по одній адресі пам’яті кожен, і тому кожен вказує на одну адресу в пам’яті.

Як група, вказівники запам'ятовують та згадують адреси пам'яті, підкоряючись кожній вашій команді ad nauseum.

Ти їх король.

Покажчики в 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;

  • Щоб отримати адресу змінної, ви використовуєте префікс & символ.

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 #, будь ласка.
Michael Puckett 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

IntPtrЄ типом значення , який в основному використовується для утримання адреси пам'яті або ручки. Покажчик є адресою пам'яті. Вказівник може бути введений (наприклад int*) або нетипізований (наприклад void*). Windows , ручка являє собою значення , яке, як правило , той же розмір (або менше) , ніж адреса пам'яті і являє собою системний ресурс (наприклад , файл або вікно).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.