2010-11-24 3 views
2

Ab FW 4.0, die IntPtr structure hat die Add Methode:Die neue Methode IntPtr.Add - fehle ich den Punkt des Int?

public static IntPtr Add(
    IntPtr pointer, 
    int offset 
) 

Das ist sehr gut, da es hatten alle diese Fragen auf IntPtr Mathematik zu adressieren angenommen hat, wir (1, 2, wahrscheinlich mehr).

Aber warum ist das offsetint?
Muss es nicht IntPtr sein? Ich kann mir leicht vorstellen, einen 64-Bit-Zeiger um einen Wert zu versetzen, der außerhalb des Bereichs int liegt.


Betrachten wir zum Beispiel Marshal.OffsetOf:

public static IntPtr OffsetOf(
    Type t, 
    string fieldName 
) 

Es gibt einen IntPtr als Offset zu dem Strukturelement. Was macht Sinn! Und Sie können diesen Offset nicht einfach mit der neuen Methode Add verwenden. Sie müssten es in Int64 umwandeln und dann Add mehrmals in einer Schleife aufrufen.

Auch scheint es zu töten die Idee von IntPtr.Size irrelevant für eine ordnungsgemäß geschriebene Anwendung. Sie müssen den Versatz auf einen bestimmten Typ umwandeln, z. B. Int64. An diesem Punkt müssen Sie mit dem Verwalten des Größenunterschieds beginnen. Und was passiert, wenn 128-Bit IntPtr erscheint.


Meine Frage hier ist, warum?
Bin ich in meinen Schlussfolgerungen richtig, oder fehlt mir der Punkt?

Antwort

5

Es entspricht einer Einschränkung in der x64-Architektur. Die relative Adressierung ist auf einen vorzeichenbehafteten 32-Bit-Offset-Wert beschränkt. Matt Pietrek erwähnt dies in this article (in der Nähe von "Glücklicherweise ist die Antwort nein"). Diese Einschränkung erklärt auch, warum .NET-Objekte im 64-Bit-Modus immer noch auf 2 GB beschränkt sind. In ähnlicher Weise sind in nativen x64 C/C++ - Code Speicherzuweisungen ebenfalls beschränkt. Es ist nicht so, dass es unmöglich ist, die Verschiebung könnte in einem 64-Bit-Register gespeichert werden, es ist nur, dass dies Array-Indizierung zu einem teureren Los machen würde.

Der mysteriöse Rückgabetyp von Marshal.OffsetOf() ist wahrscheinlich ein Eckfall. Eine verwaltete Struktur könnte nach der Anwendung von [StructLayout] und [MarshalAs], die größer als 2 GB ist, zu einer nicht verwalteten Version führen.

Ja, dies würde nicht gut zu irgendeiner zukünftigen 128-Bit-Architektur passen. Aber es ist außerordentlich schwierig, die heutige Software für einen Bogen vorzubereiten, wenn niemand weiß, wie es aussehen wird. Vielleicht passt das alte Sprichwort, 16 Terabytes sollten für jeden ausreichen. Und es gibt Lose von Raum übrig, darüber hinaus zu wachsen, 2^64 ist eher eine große Zahl. Aktuelle 64-Bit-Prozessoren implementieren nur 2^48. Einige ernsthaft nicht-triviale Probleme müssen gelöst werden, bevor Maschinen sich so nahe bewegen können.

1

Wenn definieren Sie:

public static IntPtr Add(IntPtr pointer, IntPtr offset) 

dann Hinzufügen einer 32 Bit-Offset auf einen 64 Bit-Zeiger ist weniger lesbar, IMHO.

Auch wenn Sie

public static IntPtr Add(IntPtr pointer, long offset) 

dann definieren, das Hinzufügen einer 64 Bits zu einem 32-Bit-Zeiger-Versatz ist auch schlecht.

Übrigens, Substract gibt ein IntPtr zurück, so dass die IntPtr-Logik sowieso nicht unterbrochen ist.