Qu'est-ce qu'un IntPtr exactement?


171

En utilisant IntelliSense et en regardant le code des autres, j'ai rencontré ce IntPtrtype; chaque fois qu'il a eu besoin d'être utilisé, j'ai simplement mis nullou IntPtr.Zerotrouvé la plupart des fonctions pour fonctionner. De quoi s'agit-il exactement et quand / pourquoi est-il utilisé?

Réponses:


158

C'est un "entier de taille natif (spécifique à la plate-forme)". Il est représenté en interne void*mais exposé comme un entier. Vous pouvez l'utiliser chaque fois que vous avez besoin de stocker un pointeur non managé et que vous ne souhaitez pas utiliser de unsafecode. IntPtr.Zeroest effectivement NULL(un pointeur nul).


53
Un pointeur est quelque chose qui pointe vers une adresse en mémoire. Dans les langues gérées, vous avez des références (l'adresse peut se déplacer) tandis que dans les langues non gérées, vous avez des pointeurs (l'adresse est fixe)
Colin Mackay

93
En général (dans les langages de programmation), un pointeur est un nombre qui représente un emplacement physique en mémoire. Un pointeur nul est (presque toujours) celui qui pointe vers 0, et est largement reconnu comme "ne pointant vers rien". Puisque les systèmes ont différentes quantités de mémoire prise en charge, il ne faut pas toujours le même nombre d'octets pour contenir ce nombre, donc nous appelons un "entier de taille native" qui peut contenir un pointeur sur un système particulier.
Sam Harwell

5
+1 pour ce commentaire @ 280Z28, c'est l'explication la plus succincte des pointeurs que j'ai jamais vue.
BlueRaja - Danny Pflughoeft

9
Il s'appelle IntPtr, car pour l'utiliser à partir de code natif non managé, C / C ++, vous devrez utiliser le type analogique: intptr_t. IntPtr de C # correspond exactement à intptr_t de C / C ++. Et il est probablement implémenté en tant que intptr_t. En C / C ++, le type intptr_t a la même taille que le type void *.
Петър Петров

2
@Trap "Un type spécifique à la plate-forme utilisé pour représenter un pointeur ou une poignée." Pas un "entier spécifique à la plate-forme", une "manière spécifique à la plate-forme de représenter un pointeur ou une poignée". IntPtrest parfaitement logique, car c'est un entier (comme dans un entier mathématique) et un pointeur (comme dans un pointeur). La Intpartie a peu à voir avec le type int - c'est un concept, pas un type spécifique. Bien que pour être honnête, la seule chose que la spécification CLI dit à ce sujet est qu'il s'agit bien d'une "taille entière, native". Oh bien :)
Luaan

69

C'est un type de valeur suffisamment grand pour stocker une adresse mémoire telle qu'elle est utilisée dans un code natif ou non sécurisé, mais pas directement utilisable comme adresse mémoire dans un code managé sécurisé.

Vous pouvez utiliser IntPtr.Sizepour savoir si vous exécutez dans un processus 32 bits ou 64 bits, car ce sera respectivement 4 ou 8 octets.


16
Bon point sur la détection de la taille de l'espace d'adressage pour le processus.
Noldorin

@Noldorin Vrai, mais pas nécessairement fiable. Dans le passé, il y avait beaucoup d'architectures qui avaient plusieurs types de pointeurs, et sur Windows, IntPtrest également utilisé pour représenter des poignées qui sont 32 bits quelle que soit l'architecture (bien que Sizetoujours dit 8 dans ce cas). La spécification CLI note seulement que c'est un entier qui est de "taille native", mais cela ne dit pas grand-chose, vraiment.
Luaan le

@Luaan qui ne change vraiment rien à ma réponse, n'est-ce pas? IntPtr est ainsi appelé (et est utilisé dans toute la source CLR) comme une valeur suffisamment grande pour contenir une adresse mémoire. Il peut contenir des valeurs plus petites bien sûr. Certaines architectures ont plusieurs types de pointeurs, mais doivent en avoir un qui est le plus grand de l'ensemble.
Daniel Earwicker le

@DanielEarwicker Eh bien, ce n'est pas un problème avec une implémentation .NET actuelle, pour autant que je sache. Cependant, le problème (historique) n'est pas seulement une question de taille - les différents pointeurs peuvent être totalement incompatibles. Dans un exemple plus proche d'aujourd'hui, PAE utiliserait des adresses 64 bits même si la "taille du pointeur natif" était toujours de 32 bits. Cela revient à l'argument "Que signifie vraiment" système 32 bits "?" Nous avons maintenant des registres numériques de 256 bits et 512 bits, mais nous l'appelons toujours 64 bits. Même si vous ne pouvez pas réellement adresser 64 bits de mémoire physique avec vos "pointeurs" 64 bits. C'est le bordel.
Luaan le

1
Une partie est compliquée, mais IntPtr est toujours "un type de valeur suffisamment grand pour stocker une adresse mémoire". Ce n'est pas aussi grand que le plus grand registre matériel, pour prendre l'un de vos exemples. Ce n'est tout simplement pas pour ça. Il est suffisamment grand pour représenter une adresse mémoire. Ensuite, il y a des trucs comme ceci: stackoverflow.com/questions/12006854/ ... où nous avons le mot "pointeur" utilisé pour autre chose qu'une adresse mémoire - c'est pourquoi j'ai spécifiquement dit "adresse mémoire".
Daniel Earwicker le

48

Voici un exemple:

J'écris un programme C # qui s'interface avec une caméra haute vitesse. L'appareil photo a son propre pilote qui acquiert les images et les charge automatiquement dans la mémoire de l'ordinateur.

Ainsi, lorsque je suis prêt à intégrer la dernière image dans mon programme pour travailler avec, le pilote de la caméra me fournit un IntPtr où l'image est DÉJÀ stockée dans la mémoire physique, donc je n'ai pas à perdre de temps / ressources en créant une autre bloc de mémoire pour stocker une image déjà en mémoire. L'IntPtr me montre simplement où se trouve déjà l'image.


7
Ainsi, IntPtr simple vous permet d'utiliser un pointeur non géré (comme celui utilisé dans votre pilote de caméra) dans le code géré?
Callum Rogers

5
Oui. Dans ce cas, le pilote de la caméra utilise très probablement des pilotes non gérés sous le capot, mais pour fonctionner correctement dans le monde géré uniquement, il fournit l'IntPtr pour me permettre de travailler avec les données en toute sécurité.
bufferz

3
Alors pourquoi ne vous rendrait-il pas simplement un flux (tableau d'octets)? Pourquoi est-il dangereux ou impossible de renvoyer la valeur?
The Muffin Man

35

Une interprétation directe

Un IntPtr est un entier qui a la même taille qu'un pointeur .

Vous pouvez utiliser IntPtr pour stocker une valeur de pointeur dans un type non pointeur. Cette fonctionnalité est importante dans .NET car l'utilisation de pointeurs est très sujette aux erreurs et donc illégale dans la plupart des contextes. En permettant à la valeur du pointeur d'être stockée dans un type de données «sécurisé», la plomberie entre les segments de code non sécurisés peut être implémentée dans un code de haut niveau plus sûr - ou même dans un langage .NET qui ne prend pas directement en charge les pointeurs.

La taille d'IntPtr est spécifique à la plate-forme, mais ce détail doit rarement être pris en compte, car le système utilisera automatiquement la taille correcte.

Le nom «IntPtr» est déroutant - quelque chose comme cela Handleaurait pu être plus approprié. Ma première estimation était que "IntPtr" était un pointeur vers un entier. La documentation MSDN d'IntPtr entre dans des détails quelque peu cryptiques sans jamais donner beaucoup d'informations sur la signification du nom.

Une perspective alternative

An IntPtrest un pointeur avec deux limitations:

  1. Il ne peut pas être directement déréférencé
  2. Il ne connaît pas le type des données vers lesquelles il pointe.

En d'autres termes, un IntPtrest juste comme un void*- mais avec la fonctionnalité supplémentaire qu'il peut (mais ne devrait pas) être utilisé pour l'arithmétique de base des pointeurs.

Pour déréférencer un IntPtr, vous pouvez soit le convertir en un vrai pointeur (une opération qui ne peut être effectuée que dans des contextes «non sûrs»), soit le transmettre à une routine d'assistance telle que celles fournies par la InteropServices.Marshalclasse. L'utilisation de la Marshalclasse donne l'illusion de la sécurité puisqu'elle ne vous oblige pas à être dans un contexte explicite «dangereux». Cependant, cela ne supprime pas le risque de plantage inhérent à l'utilisation de pointeurs.


2
Il existe un précédent pour le nom "intptr" du standard C99 du langage de programmation "C". linux.die.net/man/3/intptr_t .
Brent Bradburn

17

Qu'est-ce qu'un pointeur?

Dans toutes les langues, un pointeur est un type de variable qui stocke une adresse mémoire, et vous pouvez soit leur demander de vous indiquer l' adresse sur laquelle ils pointent ou la valeur à l'adresse qu'ils pointent.

Un pointeur peut être considéré comme une sorte de marque-page. Sauf qu'au lieu d'être utilisé pour accéder rapidement à une page d'un livre, un pointeur est utilisé pour suivre ou mapper des blocs de mémoire.

Imaginez la mémoire de votre programme exactement comme un grand tableau de 65535 octets.

Les pointeurs pointent docilement

Les pointeurs mémorisent chacun une adresse mémoire et pointent donc chacun vers une seule adresse en mémoire.

En tant que groupe, les pointeurs mémorisent et rappellent les adresses de mémoire, obéissant à chacune de vos commandes ad nauseum.

Tu es leur roi.

Pointeurs en C #

Plus précisément en C #, un pointeur est une variable entière qui stocke une adresse mémoire comprise entre 0 et 65534.

Egalement spécifiques à C #, les pointeurs sont de type int et donc signés.

Cependant, vous ne pouvez pas utiliser d'adresses numérotées négativement, ni accéder à une adresse supérieure à 65534. Toute tentative de le faire lèvera une exception System.AccessViolationException.

Un pointeur appelé MyPointer est déclaré comme ceci:

int * MyPointer;

Un pointeur en C # est un entier, mais les adresses mémoire en C # commencent à 0 et s'étendent jusqu'à 65534.

Les objets pointus doivent être manipulés avec un soin tout particulier

Le mot unsafe est destiné à vous effrayer, et pour une très bonne raison: les pointeurs sont des objets pointus, et les objets pointus comme les épées, les haches, les pointeurs, etc. doivent être manipulés avec un soin particulier.

Les pointeurs permettent au programmeur de contrôler étroitement un système. Par conséquent, les erreurs commises risquent d'avoir des conséquences plus graves.

Pour utiliser des pointeurs, le code non sécurisé doit être activé dans les propriétés de votre programme et les pointeurs doivent être utilisés exclusivement dans des méthodes ou des blocs marqués comme non sécurisés.

Exemple de bloc non sécurisé

unsafe
{
    // Place code carefully and responsibly here.

}

Comment utiliser les pointeurs

Lorsque des variables ou des objets sont déclarés ou instanciés, ils sont stockés en mémoire.

  • Déclarez un pointeur à l'aide du préfixe de symbole *.

int *MyPointer;

  • Pour obtenir l'adresse d'une variable, vous utilisez le préfixe de symbole &.

MyPointer = &MyVariable;

Une fois qu'une adresse est attribuée à un pointeur, ce qui suit s'applique:

  • Sans le préfixe * pour faire référence à l'adresse mémoire pointée comme un int.

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

  • Avec le préfixe * pour obtenir la valeur stockée à l'adresse mémoire pointée.

"MyPointer is pointing at " + *MyPointer;

Étant donné qu'un pointeur est une variable contenant une adresse mémoire, cette adresse mémoire peut être stockée dans une variable pointeur.

Exemple de pointeurs utilisés avec soin et de manière responsable

    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.

    }

Notez que le type du pointeur est un int. C'est parce que C # interprète les adresses mémoire comme des nombres entiers (int).

Pourquoi est-il int au lieu de uint?

Il n'y a aucune bonne raison.

Pourquoi utiliser des pointeurs?

Les pointeurs sont très amusants. Avec une grande partie de l'ordinateur contrôlée par la mémoire, les pointeurs permettent au programmeur de mieux contrôler la mémoire de son programme.

Surveillance de la mémoire.

Utilisez des pointeurs pour lire des blocs de mémoire et surveiller la façon dont les valeurs pointées changent au fil du temps.

Modifiez ces valeurs de manière responsable et suivez la manière dont vos modifications affectent votre ordinateur.


2
65534semble très faux comme plage de pointeur. Vous devez fournir une référence.
Brent Bradburn

1
J'ai voté pour cela parce que c'est un excellent article expliquant les pointeurs. J'aimerais voir quelques références aux spécifications que vous avez mentionnées (comme commenté ci-dessus). Toutefois; cette réponse n'a rien à voir avec la question. La question portait sur System.IntPtr. J'aimerais voir la réponse mise à jour à la fin expliquant ce qu'est également un System.IntPtret comment il se rapporte aux pointeurs non sécurisés en C # s'il vous plaît.
Michael Puckett II

7

MSDN nous dit:

Le type IntPtr est conçu pour être un entier dont la taille est spécifique à la plate-forme. Autrement dit, une instance de ce type devrait être 32 bits sur du matériel et des systèmes d'exploitation 32 bits, et 64 bits sur du matériel et des systèmes d'exploitation 64 bits.

Le type IntPtr peut être utilisé par les langages qui prennent en charge les pointeurs et comme moyen courant de faire référence aux données entre les langages qui prennent et ne prennent pas en charge les pointeurs.

Les objets IntPtr peuvent également être utilisés pour contenir des poignées. Par exemple, les instances d'IntPtr sont largement utilisées dans la classe System.IO.FileStream pour contenir des descripteurs de fichiers.

Le type IntPtr est conforme CLS, alors que le type UIntPtr ne l'est pas. Seul le type IntPtr est utilisé dans le Common Language Runtime. Le type UIntPtr est fourni principalement pour maintenir la symétrie architecturale avec le type IntPtr.

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


5

Eh bien, c'est la page MSDN qui traite IntPtr.

La première ligne se lit comme suit:

Un type spécifique à la plate-forme utilisé pour représenter un pointeur ou une poignée.

Quant à ce qu'est un pointeur ou une poignée, la page continue à indiquer:

Le type IntPtr peut être utilisé par les langages qui prennent en charge les pointeurs et comme moyen courant de faire référence aux données entre les langages qui prennent et ne prennent pas en charge les pointeurs.

Les objets IntPtr peuvent également être utilisés pour contenir des poignées. Par exemple, les instances d'IntPtr sont largement utilisées dans la classe System.IO.FileStream pour contenir des descripteurs de fichiers.

Un pointeur est une référence à une zone de mémoire qui contient certaines données qui vous intéressent.

Un handle peut être un identifiant pour un objet et est passé entre les méthodes / classes lorsque les deux côtés ont besoin d'accéder à cet objet.


2

An IntPtrest un type de valeur principalement utilisé pour contenir des adresses mémoire ou des descripteurs. Un pointeur est une adresse mémoire. Un pointeur peut être tapé (par exemple int*) ou non typé (par exemple void*). Un handle Windows est une valeur qui est généralement de la même taille (ou plus petite) qu'une adresse mémoire et représente une ressource système (comme un fichier ou une fenêtre).

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.