2010-11-24 38 views
2

A partir de 4.0 FW, le IntPtr structure a la méthode Add:La nouvelle méthode IntPtr.Add - Ai-je manqué le point de l'int?

public static IntPtr Add(
    IntPtr pointer, 
    int offset 
) 

Ce qui est génial, car il est censé répondre à toutes ces questions sur les mathématiques IntPtr nous avons eu (1, 2, probablement plus). Mais pourquoi est le offsetint?
Est-ce que ce ne doit pas être IntPtr? Je peux facilement imaginer compenser un pointeur de 64 bits par une valeur qui est au-delà de la plage int.


Par exemple, considérons Marshal.OffsetOf:

public static IntPtr OffsetOf(
    Type t, 
    string fieldName 
) 

Il retourne un IntPtr que le décalage de l'élément de structure. Ce qui est parfaitement logique! Et vous ne pouvez pas facilement utiliser ce décalage avec la nouvelle méthode Add. Vous devez le convertir en Int64, puis appeler le Add plusieurs fois en boucle.

En outre, il semble tuer l'idée même du IntPtr.Size étant sans importance pour une application correctement écrite. Vous devrez convertir le décalage en un type particulier, tel que Int64, auquel cas vous devez commencer à gérer la différence de taille. Et image ce qui se passera lorsque IntPtr 128 bits apparaît.


Ma question est ici, pourquoi?
Est-ce que je suis correct dans mes conclusions, ou est-ce que je manque le point?

Répondre

5

Cela correspond à une restriction dans l'architecture x64. L'adressage relatif est limité à une valeur de décalage de 32 bits signée. Matt Pietrek mentionne ceci dans this article (près de "Heureusement, la réponse est non"). Cette restriction explique également pourquoi les objets .NET sont toujours limités à 2 Go en mode 64 bits. De même, en natif x64 C/C++, les allocations de mémoire de code sont également limitées. Ce n'est pas que ce soit impossible, le déplacement pourrait être stocké dans un registre 64 bits, c'est juste que cela rendrait l'indexation d'un réseau plus onéreuse.

Le type de retour mystérieux de Marshal.OffsetOf() est probablement un cas d'angle. Une structure gérée peut générer une version non gérée après l'application de [StructLayout] et [MarshalAs] supérieure à 2 Go.Oui, cela ne correspondrait pas bien à une future architecture 128 bits. Mais il est extraordinairement difficile de préparer le logiciel d'aujourd'hui pour une arche quand personne ne sait à quoi cela va ressembler. Peut-être que le vieil adage convient, 16 téraoctets devraient suffire à n'importe qui. Et il ya lots de la pièce à gauche pour grandir au-delà de cela, 2^64 est plutôt un grand nombre. Les processeurs 64 bits actuels n'implémentent que 2^48. Certains problèmes sérieux non-triviaux doivent être résolus avant que les machines puissent bouger aussi près.

1

Si vous définissez seulement:

public static IntPtr Add(IntPtr pointer, IntPtr offset) 

puis, en ajoutant un 32 bits de décalage à un pointeur 64 bits est moins lisible, à mon humble avis.

Encore une fois, si vous définissez

public static IntPtr Add(IntPtr pointer, long offset) 

puis, en ajoutant 64 bits de décalage à un pointeur 32 bits est aussi mauvais. Par ailleurs, Le sous-résumé renvoie un IntPtr, de sorte que la logique IntPtr n'est pas interrompue de toute façon.