2015-08-10 3 views
5

Ich habe C-Sprache gelernt und folgte "Let Us C" von Yashavant P. Kanetkar.Warum können wir Zeiger nicht vergleichen, die nicht auf Elemente innerhalb desselben Arrays zeigen?

Es gibt eine Zeile im Zeiger-Kapitel, die besagt, dass wir nur weniger als (<) und größer als (>) die Zeiger vergleichen können, die auf die Elemente innerhalb desselben Arrays zeigen.

Warum ist der Vergleich beliebiger Zeiger nicht zulässig?

+1

Weil C diesen Vergleich nicht definiert. – this

+2

Es gibt einige Architekturen, wo dies nicht funktionieren würde - der Standard deckt daher diesen Fall ab, obwohl es in den meisten gängigen Architekturen funktionieren könnte. Übrigens sind die Kanetkar-Bücher im Allgemeinen schrecklich - in Betracht ziehen, [von einem anständigen C-Buch] (http://stackoverflow.com/questions/562303/the-definitive-c-book-guide-and-list) zu lernen. –

+0

Haben alle Sprachen, die Zeiger unterstützen, diese Undefinierbarkeit? – ashwani

Antwort

13

Weil C keine Annahme über die Host-Maschine macht, und nichts hält letzteres davon ab, zwei Arrays in zwei völlig getrennten Adressräumen zuzuweisen.

It's not just about theoretical exotic architectures either. 16-Bit-Compiler für x86-Maschinen bieten zwei Arten von Zeigern. Nahe Zeiger waren 16 Bits breit und benahmen sich, wie Sie sie erwarten würden; Sie können jedoch nur auf 64 KB RAM zugreifen. Wenn Sie auf mehr als 64 KB RAM zugreifen wollten (nicht 64 KB für jeden Block: 64 KB für das gesamte Programm!), Mussten Sie weit entfernte Zeiger verwenden.

Far-Zeiger waren 32 Bits breit und bestanden aus zwei 16-Bit-Hälften, dem und dem offset; zum Beispiel 1234:0000 ist ein Zeiger, der Segment 0x1234 und Offset 0 hat. Die tatsächliche Speicheradresse war segment * 16 + offset. In der Regel hat farmalloc einen Zeiger mit Null-Offset zurückgegeben, und Zeigerarithmetik hat nur den Offset geändert. So könnten Sie haben

char *x = farmalloc(64);  // returns 1234:0000 for address 0x12340 
char *y = farmalloc(64);  // returns 1238:0000 for address 0x12380 

Nun, wenn Sie x + 128 berechnen, ist das Ergebnis 1234:0080, für Adresse 0x123C0. Es vergleicht less than 1238: 0000 (weil 0x1234 < 0x1238), aber es zeigt auf eine höhere Adresse (weil 0x123C0> 0x1238).

Warum? Weil das Summieren von 128 zu x, das auf ein 64-Byte-Objekt zeigte, ein undefiniertes Verhalten war.

Die memory model Compilereinstellungen definierten, ob die Standardgröße von Zeigern nahe oder weit war. Zum Beispiel hatte das "kleine" Speichermodell 64 K für Code und 64 K für alle globalen Variablen, automatische Variablen (Stack) und den Malloc-Heap. Beachten Sie, dass sich der Code in einem separaten Segment befand, sodass Sie nicht einfach einen 16-Bit-Funktionszeiger ("in der Nähe") verwenden und ihn auf Maschinensprache dereferenzieren konnten! Wenn Sie das tun mussten, mussten Sie den Compiler bitten, den Code in das gleiche Segment wie den Rest zu stellen (das "winzige" Speichermodell).

Bei einigen Speichermodellen hatte der Compiler immer weit entfernte Zeiger, was langsamer war, aber notwendig, wenn Daten + Stack + Heap 64 KB überschritten ("kompakte" oder "große" Speichermodelle).

Die Größe des Codes und der Daten war ebenfalls unterschiedlich, so dass Sie ein Speichermodell haben könnten, in dem Funktionszeiger nahe, aber Datenzeiger weit sind oder umgekehrt. Dies ist der Fall mit dem oben erwähnten "kompakten" Modell (64K Code-Limit, aber weit Zeiger für Daten) und dem Dual "Medium" -Modell (weit Zeiger für Code, 64K Datenlimit).

Es gab auch eine Möglichkeit für Compiler, flache 32-Bit-Zeiger für alles zu verwenden (das sogenannte "riesige" Speichermodell), aber es war langsam und niemand benutzte es.

+0

"Weil C keine Annahmen über die Host-Maschine macht" - können Sie bitte diesen Teil erklären..ich habe es nicht verstanden. Was ist eine Host-Maschine? – ashwani

+4

@ user132458 es ist die Maschine, die am Ende läuft Ihr Programm. – Quentin

+1

Ich habe eine Verwirrung. Nehmen wir an, der Zeiger p1 zeigt auf den Speicherplatz 1000, der auf ein Element innerhalb des Feldes a zeigt, und der Zeiger p2 zeigt auf den Speicherplatz 5000, der auf ein Element innerhalb des Feldes b zeigt. In diesem Fall sollte nicht (p1 ashwani

5

Undefined behavior gilt hier. Sie können zwei Zeiger nicht vergleichen, es sei denn, sie zeigen beide auf das gleiche Objekt oder auf das erste Element nach dem Ende dieses Objekts.