Was ist der Unterschied zwischen Fernzeigern und Nahzeigern?

Lesezeit: 10 Minuten

Madhans Benutzeravatar
Madhan

Kann mir jemand den Unterschied zwischen sagen far Zeiger und near Zeiger in C?

Benutzeravatar von Michael Foukarakis
Michael Foukarakis

Auf einer segmentierten 16-Bit-x86-Speicherarchitektur werden vier Register verwendet, um auf die jeweiligen Segmente zu verweisen:

  • DS → Datensegment
  • CS → Codesegment
  • SS → Stapelsegment
  • ES → zusätzliches Segment

Eine logische Adresse auf dieser Architektur wird geschrieben segment:offset. Nun zur Beantwortung der Frage:

  • Near-Zeiger beziehen sich (als Offset) auf das aktuelle Segment.

  • Far-Zeiger verwenden Segmentinformationen und einen Offset, um über Segmente hinweg zu zeigen. Um sie zu verwenden, muss also DS oder CS auf den angegebenen Wert geändert werden, der Speicher wird dereferenziert und dann der ursprüngliche Wert von DS/CS wiederhergestellt. Beachten Sie, dass die Zeigerarithmetik auf ihnen den Segmentteil des Zeigers nicht ändert, sodass ein Überlauf des Offsets ihn einfach umbricht.

  • Und dann gibt es riesige Zeiger, die so normalisiert sind, dass sie das höchstmögliche Segment für eine bestimmte Adresse haben (im Gegensatz zu fernen Zeigern).

Auf 32-Bit- und 64-Bit-Architekturen verwenden Speichermodelle Segmente unterschiedlich oder gar nicht.

  • Dies wäre klarer, wenn Sie erklären würden, was ein Segment (und gegebenenfalls ein Offset) ist. “Segmente”, wie sie von DOS verwendet werden, sind ein wenig geheimnisvoll, imho.

    – Quark

    17. November 2009 um 16:28 Uhr

Benutzeravatar von Lundin
Lundin

Da niemand DOS erwähnt hat, lassen Sie uns alte DOS-PC-Computer vergessen und dies von einem allgemeinen Standpunkt aus betrachten. Dann geht es ganz vereinfacht so:


Jede CPU hat einen Datenbus, das ist die maximale Datenmenge, die die CPU in einem einzigen Befehl verarbeiten kann, dh gleich der Größe ihrer Register. Die Datenbusbreite wird in Bit ausgedrückt: 8 Bit oder 16 Bit oder 64 Bit usw. Daher kommt auch der Begriff „64-Bit-CPU“ – er bezieht sich auf den Datenbus.

Jede CPU hat einen Adressbus, ebenfalls mit einer bestimmten Busbreite, ausgedrückt in Bits. Jede Speicherzelle in Ihrem Computer, auf die die CPU direkt zugreifen kann, hat eine eindeutige Adresse. Der Adressbus ist groß genug, um den gesamten adressierbaren Speicher abzudecken, den Sie haben.

Wenn ein Computer beispielsweise 65536 Bytes adressierbaren Speicher hat, können Sie diese mit einem 16-Bit-Adressbus abdecken, 2^16 = 65536.

Meistens, aber nicht immer, ist die Datenbusbreite so breit wie die Adressbusbreite. Es ist schön, wenn sie die gleiche Größe haben, da es sowohl den CPU-Befehlssatz als auch die dafür geschriebenen Programme übersichtlicher hält. Wenn die CPU eine Adresse berechnen muss, ist es praktisch, wenn diese Adresse klein genug ist, um in die CPU-Register zu passen (oft als Indexregister bezeichnet, wenn es um Adressen geht).

Die nicht standardmäßigen Schlüsselwörter far und near werden verwendet, um Zeiger auf Systemen zu beschreiben, bei denen Sie Speicher über die normale Breite des CPU-Adressbusses hinaus adressieren müssen.

Beispielsweise könnte es für eine CPU mit 16-Bit-Datenbus praktisch sein, auch einen 16-Bit-Adressbus zu haben. Derselbe Computer benötigt jedoch möglicherweise auch mehr als 2 ^ 16 = 65536 Bytes = 64 KB adressierbaren Speicher.

Die CPU verfügt dann normalerweise über spezielle Anweisungen (die etwas langsamer sind), die es ihr ermöglichen, Speicher über diese 64 KB hinaus zu adressieren. Beispielsweise kann die CPU ihren großen Speicher aufteilen n Seiten (manchmal auch genannt Banken, Segmente und andere solche Begriffe, die von einer CPU zur anderen etwas anderes bedeuten können), wobei jede Seite 64 KB groß ist. Es wird dann ein “Seiten”-Register haben, das zuerst gesetzt werden muss, bevor dieser erweiterte Speicher adressiert wird. In ähnlicher Weise hat es spezielle Anweisungen beim Aufrufen/Zurückkehren von Unterroutinen im erweiterten Speicher.

Damit ein C-Compiler beim Umgang mit einem solchen erweiterten Speicher die richtigen CPU-Anweisungen generiert, muss der nicht standardmäßige near und far Schlüsselwörter wurden erfunden. Nicht standardisiert, da sie nicht vom C-Standard spezifiziert sind, aber de facto Industriestandard sind und fast jeder Compiler sie in irgendeiner Weise unterstützt.

far bezieht sich auf Speicher, der sich im erweiterten Speicher jenseits der Breite des Adressbusses befindet. Da es sich auf Adressen bezieht, verwenden Sie es meistens beim Deklarieren von Zeigern. Zum Beispiel: int * far x; bedeutet “gib mir einen Zeiger, der auf den erweiterten Speicher zeigt”. Und der Compiler wird dann wissen, dass er die speziellen Anweisungen generieren sollte, die für den Zugriff auf diesen Speicher erforderlich sind. Ebenso Funktionszeiger, die verwenden far erzeugt spezielle Anweisungen zum Springen/Zurückkehren aus dem erweiterten Speicher. Wenn Sie nicht verwendet haben far dann würden Sie einen Zeiger auf den normalen, adressierbaren Speicher erhalten, und Sie würden am Ende auf etwas ganz anderes zeigen.

near ist hauptsächlich aus Konsistenzgründen enthalten far; es bezieht sich auf alles im adressierbaren Speicher, was einem regulären Zeiger entspricht. Es ist also hauptsächlich ein nutzloses Schlüsselwort, abgesehen von einigen seltenen Fällen, in denen Sie sicherstellen möchten, dass Code im standardmäßig adressierbaren Speicher platziert wird. Sie könnten dann etwas explizit als kennzeichnen near. Der typischste Fall ist die Low-Level-Hardwareprogrammierung, bei der Sie Interrupt-Serviceroutinen schreiben. Sie werden von der Hardware aus einem Interrupt-Vektor mit fester Breite aufgerufen, die gleich der Breite des Adressbusses ist. Das bedeutet, dass sich die Interrupt-Service-Routine im standardmäßig adressierbaren Speicher befinden muss.


Die bekannteste Verwendung von far und near ist vielleicht der erwähnte alte MS-DOS-PC, der heutzutage als ziemlich alt und daher von geringem Interesse gilt.

Aber diese Schlüsselwörter gibt es auch auf moderneren CPUs! Vor allem in eingebetteten Systemen, wo sie für so ziemlich jede 8- und 16-Bit-Mikrocontroller-Familie auf dem Markt existieren, da diese Mikrocontroller typischerweise eine Adressbusbreite von 16 Bit, aber manchmal mehr als 64 kB Speicher haben.

Wann immer Sie eine CPU haben, bei der Sie Speicher über die Adressbusbreite hinaus adressieren müssen, werden Sie dies benötigen far und near. Im Allgemeinen sind solche Lösungen jedoch verpönt, da es ziemlich mühsam ist, darauf zu programmieren und immer den erweiterten Speicher zu berücksichtigen.

Einer der Hauptgründe für die Entwicklung des 64-Bit-PCs war, dass die 32-Bit-PCs an den Punkt gekommen waren, an dem ihre Speichernutzung an die Grenze des Adressbusses stieß: Sie konnten nur noch 4 GB RAM adressieren. 2^32 = 4,29 Milliarden Bytes = 4 GB. Um die Nutzung von mehr Arbeitsspeicher zu ermöglichen, bestand die Wahl dann entweder darin, wie zu DOS-Zeiten auf eine lästige Speichererweiterungslösung zurückzugreifen oder die Rechner samt Adressbus auf 64 Bit zu erweitern.

  • “wird verwendet, um Zeiger auf Systemen zu beschreiben, bei denen Sie Speicher über die normale CPU-Adressbusbreite hinaus adressieren müssen” – nein, der 8086 hatte einen 20-Bit-Adressbus. Bei der Speichersegmentierung ging es darum, breitere Adressen zu generieren, ohne die Zeigergröße zu vergrößern. “Daher kommt der Begriff “64-Bit-CPU” – er bezieht sich auf den Datenbus.” — nein, es bezieht sich auf die ganzzahlige Registerbreite. Datenbusse sind normalerweise breiter, wobei der L1-Cache ein SIMD-Register mit 128 Bit laden kann und höhere Ebenen der Speicherhierarchie sogar noch breiter sind. Adressbusse sind normalerweise schmaler; Die MMU verfügt möglicherweise nicht über einen physischen 64-Bit-Adressraum.

    – Kartoffelklatsche

    30. Dezember 2016 um 9:01 Uhr

  • Bezüglich des Vorstoßes, den 64-Bit-PC zu entwickeln, siehe Linus Torvalds über PAE.

    – Ruslan

    16. April 2018 um 14:30 Uhr

  • Hin und wieder werden Sie Code finden, der so sehr auf Portabilität ausgelegt ist, dass er Compiler wo umgeht near und far sind noch Stichworte. So finden Sie Dinge wie 3D-Projektionsmatrizen mit hither und yon Clipping-Ebenen

    – Rickster

    17. April 2018 um 5:01 Uhr

Benutzeravatar von Pablo Santa Cruz
Pablo Santa Cruz

Far- und Near-Zeiger wurden in alten Plattformen wie DOS verwendet.

Ich glaube nicht, dass sie auf modernen Plattformen relevant sind. Aber man kann sie lernen hier und hier (wie in anderen Antworten gezeigt). Grundsätzlich ein weit Pointer ist eine Möglichkeit, den adressierbaren Speicher in einem Computer zu erweitern. IE, adressieren Sie mehr als 64 KB Speicher in einer 16-Bit-Plattform.

  • Ich glaube, dass einige Betriebssysteme auf einem 32-Bit-System auf mehr als 4 GB Speicher zugreifen können. In diesem Fall sind solche erweiterten Zeigertypen notwendig. Es kommt jedoch selten vor, dass das Betriebssystem Anwendungen im Benutzermodus in einer solchen Umgebung Zugriff auf mehr als 4 GB gewährt.

    – PP.

    17. November 2009 um 16:20 Uhr

  • Ja. Das liegt daran, dass der physische x86-Adressbus für 32-Bit-Maschinen 36 Bit breit ist. Aber der logische Adressraum ist immer noch auf 32 Bit begrenzt. Die PAE-Erweiterungen stellen den “zusätzlichen” Speicher zur Verfügung (tatsächlich durch Bankswitching, IIRC). Das eigentliche Problem ist, dass die MMU mehr oder weniger ferngehalten wird (kein mmap, COW usw.). Aber der Speicher kann als Festplattenpuffer für Apps verwendet werden, die ihre eigene Pufferung durchführen. Oder das Betriebssystem, das das Bankswitching und die MMU-Manipulation handhabt.

    – Wildpässer

    29. Januar 2012 um 16:53 Uhr

  • PAE verwendet zusätzliche Bits im PTE der MMU, um vier zusätzliche Bits von Seitenrahmeninformationen zu adressieren. Einen Bankwechsel gibt es meines Wissens nicht.

    – Samuel A. Falvo II

    28. April 2017 um 22:08 Uhr


Benutzeravatar von aman singh bhandari
aman singh bhandari

Ein Zeiger enthält grundsätzlich Adressen. Wie wir alle wissen, ist die Speicherverwaltung von Intel in 4 Segmente unterteilt. Wenn sich also eine Adresse, auf die ein Zeiger zeigt, innerhalb desselben Segments befindet, handelt es sich um einen Near-Zeiger und erfordert daher nur 2 Bytes für den Offset. Wenn andererseits ein Zeiger auf eine Adresse zeigt, die außerhalb des Segments liegt (d. h. in einem anderen Segment), dann ist dieser Zeiger ein Far-Zeiger. Es besteht aus 4 Bytes: zwei für Segment und zwei für Offset.

Vier Register werden verwendet, um auf vier Segmente in der segmentierten 16-Bit-x86-Speicherarchitektur zu verweisen. DS (Datensegment), CS (Codesegment), SS (Stapelsegment) und ES (zusätzliches Segment). Eine logische Adresse auf dieser Plattform wird segment:offset im Hexadezimalformat geschrieben.

Near-Zeiger beziehen sich (als Offset) auf das aktuelle Segment.

Far-Zeiger verwenden Segmentinformationen und einen Offset, um über Segmente hinweg zu zeigen. Um sie zu verwenden, muss also DS oder CS auf den angegebenen Wert geändert werden, der Speicher wird dereferenziert und dann der ursprüngliche Wert von DS/CS wiederhergestellt. Beachten Sie, dass die Zeigerarithmetik auf ihnen den Segmentteil des Zeigers nicht ändert, sodass ein Überlauf des Offsets ihn einfach umbricht.

Und dann gibt es riesige Zeiger, die so normalisiert sind, dass sie das höchstmögliche Segment für eine bestimmte Adresse haben (im Gegensatz zu fernen Zeigern).

Auf 32-Bit- und 64-Bit-Architekturen verwenden Speichermodelle Segmente unterschiedlich oder gar nicht.

  • Nun, diese Register werden tatsächlich für verschiedene Zwecke verwendet. Wie Sie selbst erwähnt haben, werden CODE, DATA, STACK, EXTRA registriert. Natürlich gibt es auch AX, BX, DX, CX. Aber CS war für CODE, DS war für DATA, SS war für Stack und ES war für die Erweiterung bestehender Daten und Codevariablen. AX/BX/CX/DX war zu DOS-Zeiten sehr wichtig. Wie jedes andere Register. Wenn Interrupt-Funktionen (INT) aufgerufen wurden, stützten sich viele von ihnen auf tatsächliche Registrierungswerte.

    – Oskars Lusis

    11. Januar 2016 um 15:20 Uhr


Nun, in DOS war es irgendwie lustig, mit Registern umzugehen. Und Segmente. Alles über maximale Zählkapazitäten von RAM.

Heute ist es ziemlich egal. Alles, was Sie lesen müssen, ist der Unterschied zwischen virtuellem/Benutzerraum und Kernel.

Seit win nt4 (als sie Ideen von *nix stahlen) fingen Microsoft-Programmierer an, sogenannte Benutzer-/Kernel-Speicherplätze zu verwenden. Und seitdem den direkten Zugriff auf physische Controller vermieden. Seitdem ist auch ein Problem mit dem direkten Zugriff auf Speichersegmente verschwunden. – Alles wurde R/W durch OS.

Wenn Sie jedoch darauf bestehen, Far/Near-Zeiger zu verstehen und zu manipulieren, schauen Sie sich die Linux-Kernelquellen an und wie sie funktionieren – Sie werden später zurückkommen, denke ich.

Und wenn Sie immer noch CS (Code Segment)/DS (Data Segment) in DOS verwenden müssen. Schau dir diese …… an:

https://en.wikipedia.org/wiki/Intel_Memory_Model
http://www.digitalmars.com/ctg/ctgMemoryModel.html

Ich möchte auf die perfekte Antwort unten hinweisen.. von Lundin. Ich war zu faul, richtig zu antworten. Lundin gab sehr detaillierte und vernünftige Erklärungen “Daumen hoch”!

  • Nun, diese Register werden tatsächlich für verschiedene Zwecke verwendet. Wie Sie selbst erwähnt haben, werden CODE, DATA, STACK, EXTRA registriert. Natürlich gibt es auch AX, BX, DX, CX. Aber CS war für CODE, DS war für DATA, SS war für Stack und ES war für die Erweiterung bestehender Daten und Codevariablen. AX/BX/CX/DX war zu DOS-Zeiten sehr wichtig. Wie jedes andere Register. Wenn Interrupt-Funktionen (INT) aufgerufen wurden, stützten sich viele von ihnen auf tatsächliche Registrierungswerte.

    – Oskars Lusis

    11. Januar 2016 um 15:20 Uhr


1412410cookie-checkWas ist der Unterschied zwischen Fernzeigern und Nahzeigern?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy