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.
Weil C diesen Vergleich nicht definiert. – this
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. –
Haben alle Sprachen, die Zeiger unterstützen, diese Undefinierbarkeit? – ashwani