Warum kann ich nicht zwei IntPtrs mit und vergleichen?

8

Ich habe derzeit ein Problem mit unsicheren Zeigern, das ein Compiler-Bug zu sein scheint.

Hinweis: Das Problem liegt nicht in der Tatsache, dass ich Zeiger und unsicheren Code verwende; Der Code funktioniert ziemlich gut. Das Problem hängt mit einem bestätigten Compiler-Fehler zusammen, der unter bestimmten Umständen die Kompilierung von legalem Code verweigert. Wenn Sie an diesem Problem interessiert sind, besuchen Sie meine andere Frage

Da mein Problem mit der Deklaration von Zeigervariablen zusammenhängt, habe ich beschlossen, das Problem zu umgehen und stattdessen IntPtr zu verwenden und bei Bedarf zu tatsächlichen Zeigern zu konvertieren.

Allerdings habe ich bemerkt, dass ich sowas nicht tun kann:

%Vor%

Die Operatoren > und < scheinen nicht für IntPtr definiert zu sein. Beachten Sie, dass ich tatsächlich zwei tatsächliche Zeiger vergleichen kann.

IntPtr hat eine .ToInt64() -Methode. Dies ergibt jedoch einen signierten Wert, der beim Vergleich mit > und < falsche Werte zurückgibt, wenn positive und negative Werte beteiligt sind.

Um ehrlich zu sein, ich verstehe nicht wirklich, was es für eine .ToInt64() -Methode gibt, die einen signierten Wert zurückgibt, wenn man bedenkt, dass Zeiger Vergleiche werden unsigned durchgeführt, aber das ist nicht meine Frage.

Man könnte argumentieren, dass IntPtr s undurchsichtige Handles sind und es daher sinnlos ist, sie mit > und < zu vergleichen. Ich möchte jedoch darauf hinweisen, dass IntPtr Additions- und Subtraktionsmethoden hat, was bedeutet, dass es tatsächlich einen Ordnungsbegriff für IntPtr gibt und daher > und < tatsächlich sinnvoll sind.

Ich denke, ich könnte das Ergebnis von ToInt64() auf ein ulong umwandeln und dann das IntPtr mit einem Zeiger vergleichen und dann den Vergleich durchführen, aber es lässt mich denken, warum nicht > und < definiert für IntPtr .

Warum kann ich zwei IntPtr s nicht direkt vergleichen?

    
Panda Pajama 07.04.2015, 06:15
quelle

3 Antworten

6

IntPtr wurde immer ein wenig vernachlässigt. Bis .NET 4.0 gab es nicht einmal die Add / operator+ und Subtract / operator- .

Jetzt ... Wenn Sie zwei Zeiger vergleichen möchten, müssen Sie sie in long umwandeln, wenn sie IntPtr sind, oder in ulong , wenn sie UIntPtr sind. Beachten Sie, dass Sie unter Windows nur dann ein UIntPtr benötigen, wenn Sie ein 32-Bit-Programm mit der Option /3GB verwenden, da andernfalls ein 32-Bit-Programm nur die unteren 2 GB des Adressraums und für 64-Bit-Programme viel verwenden kann Es werden weniger als 64 Bit Adressraum verwendet ( 48 Bit zu diesem Zeitpunkt).

Klar, wenn Sie Kernel-Programmierung in .NET tun, ändert sich das :-) (Ich jocke hier, ich hoffe :-))

Aus dem Grund, warum IntPtr gegenüber UIntPtr bevorzugt wird: Ссылка

  

Der Typ IntPtr ist CLS-kompatibel, der Typ UIntPtr nicht. In der Common Language Runtime wird nur der IntPtr-Typ verwendet. Der Typ UIntPtr wird hauptsächlich bereitgestellt, um die Architektursymmetrie mit dem Typ IntPtr zu erhalten.

Es gibt einige Sprachen, die nicht zwischen signierten und unsignierten Typen unterscheiden. .NET wollte sie unterstützen.

Erledige einige Tests mit

%Vor%

(Ich konnte sogar meinen Grafikadapter abstürzen :-))

%Vor%

Ich konnte fast 4 GB Speicher mit einem 32-Bit-Programm (auf einem 64-Bit-Betriebssystem) zuweisen (so hatte ich negative IntPtr )

Und hier ist es eine Besetzung von IntPtr bis UIntPtr

%Vor%

Beachten Sie, dass dank der Funktionsweise der Zeichenerweiterung (UIntPtr)(ulong)(long)ptr nicht einfach ausgeführt werden kann, da sie bei 32 Bits unterbrochen wird.

Beachten Sie jedoch, dass nur wenige Programme & gt; 2 GB auf 32 Bits ... Ссылка

    
xanatos 07.04.2015 06:34
quelle
2

Der Vergleich von IntPtr ist sehr, sehr gefährlich. Der Hauptgrund, warum die C # -Sprache dies verbietet, obwohl die CLR kein Problem damit hat.

IntPtr wird häufig zum Speichern eines nicht verwalteten Zeigerwerts verwendet. Großes Problem ist: Zeigerwerte sind keine signierten Werte. Nur ein UIntPtr ist ein geeigneter verwalteter Typ, um sie zu speichern. Ein großes Problem mit UIntPtr ist, dass es kein CLS-konformer Typ ist. Viele Sprachen unterstützen keine vorzeichenlosen Typen. Java, JScript und frühe Versionen von VB.NET sind Beispiele. Alle Framework-Methoden verwenden daher IntPtr.

Es ist so besonders unangenehm, weil es oft ohne Probleme funktioniert. Beginnend mit 32-Bit-Versionen von Windows sind die oberen 2 GB des Adressraums für das Betriebssystem reserviert, so dass alle in einem Programm verwendeten Zeigerwerte immer & lt; = 0x7FFFFFFFF sind. Funktioniert gut in einem IntPtr.

Aber das stimmt nicht in jedem Fall. Sie könnten als 32-Bit-App im wow64-Emulator auf einem 64-Bit-Betriebssystem ausgeführt werden. Der obere 2 GB Adressraum wird vom Betriebssystem nicht mehr benötigt, sodass Sie einen Adressraum von 4 GB erhalten. Was sehr nett ist, 32-Bit-Code oft OOM in diesen Tagen. Zeigerwerte jetzt tun erhalten & gt; = 0x80000000. Und jetzt schlägt der IntPtr-Vergleich in völlig zufälligen Fällen fehl. Ein Wert von zB 0x80000100 ist eigentlich ist größer als 0x7FFFFE00, aber der Vergleich sagt, dass er kleiner ist. Nicht gut. Und es passiert nicht sehr oft, Zeigerwerte neigen dazu, ähnlich zu sein. Und es ist ziemlich zufällig, tatsächliche Zeigerwerte sind in hohem Maße unvorhersehbar.

Das ist ein Fehler, den niemand diagnostizieren kann.

Programmierer, die C oder C ++ verwenden, können diesen Fehler ebenfalls leicht machen, ihre Sprache hält sie nicht davon ab. Microsoft hat einen anderen Weg gefunden, dieses Elend zu vermeiden. Ein solches Programm muss mit einer speziellen Linker-Option um mehr als 2 GB Adressraum zu erhalten.

    
Hans Passant 07.04.2015 11:06
quelle
0

IMHO, IntPtr wurde nicht für solche Ziele wie den höheren / niedrigeren Vergleich entwickelt. Es ist die Struktur, die Speicheradresse speichert und kann nur auf Gleichheit getestet werden. Sie sollten keine relative Position von irgendetwas im Speicher berücksichtigen (was von CLI verwaltet wird). Es ist, als würde man vergleichen, welche IP in Enternet höher ist.

    
FLCL 07.04.2015 08:37
quelle

Tags und Links