web-dev-qa-db-ger.com

Was ist der Unterschied zwischen Fernzeigern und Nahzeigern?

Kann mir jemand den Unterschied zwischen far-Zeigern und near-Zeigern in C erklären?

44
Madhan

Bei einer x86-segmentierten 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 in dieser Architektur wird segment:offset geschrieben. Nun zur Beantwortung der Frage:

  • Nahe Zeiger beziehen sich (als Versatz) auf das aktuelle Segment.

  • Fernzeiger verwenden Segmentinformationen und einen Versatz, um über Segmente hinweg zu zeigen. Um sie verwenden zu können, muss DS oder CS auf den angegebenen Wert geändert werden, der Speicher wird dereferenziert und der ursprüngliche Wert von DS/CS wird wiederhergestellt. Beachten Sie, dass die Zeigerarithmetik für sie nicht den Segmentabschnitt des Zeigers ändert. Wenn Sie also den Offset überschreiten, wird er nur umbrochen.

  • Und dann gibt es riesige Zeiger, die normalisiert werden, um das höchstmögliche Segment für eine gegebene Adresse zu haben (im Gegensatz zu weiten Zeigern).

Bei 32-Bit- und 64-Bit-Architekturen verwenden Speichermodelle Segmente unterschiedlich oder überhaupt nicht.

42

Da niemand von DOS sprach, vergessen wir alte DOS-PC-Computer und betrachten dies aus einer generischen Sichtweise. Dann geht es sehr vereinfacht so:


Jede CPU verfügt über einen Datenbus, dh die maximale Datenmenge, die die CPU in einem einzigen Befehl verarbeiten kann, d. H. Gleich der Größe ihrer Register. Die Datenbusbreite wird in Bits ausgedrückt: 8 Bits oder 16 Bits oder 64 Bits usw. Hier kommt der Begriff "64-Bit-CPU" - er bezieht sich auf den Datenbus.

Jede CPU hat einen Adressbus, auch 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. 

Besitzt ein Computer beispielsweise 65536 Byte adressierbaren Speicher, können Sie diesen 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 sowohl der CPU-Befehlssatz als auch die dafür programmierten Programme übersichtlicher sind. Wenn die CPU eine Adresse berechnen muss, ist es zweckmäßig, wenn diese Adresse klein genug ist, um in die CPU-Register zu passen (oft als Indexregister bezeichnet, wenn es sich um Adressen handelt).

Die nicht standardmäßigen Schlüsselwörter far und near werden zur Beschreibung von Zeigern auf Systemen verwendet, bei denen Speicher außerhalb der normalen CPU-Adressbusbreite angesprochen werden muss.  

Beispielsweise könnte es für eine CPU mit 16-Bit-Datenbus günstig sein, auch einen 16-Bit-Adressbus zu haben. Derselbe Computer benötigt jedoch möglicherweise 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 ihnen ermöglichen, den Speicher über diese 64 kB hinaus zu adressieren. Zum Beispiel kann die CPU ihren großen Speicher in npages unterteilen (manchmal auch als banks, segmente und andere Begriffe bezeichnet, die von CPU zu CPU etwas anderes bedeuten können). wo jede seite 64kb ist. Es hat dann ein "Page" -Register, das zuerst gesetzt werden muss, bevor der erweiterte Speicher adressiert wird. In ähnlicher Weise gibt es spezielle Anweisungen, wenn Subroutinen im Erweiterungsspeicher aufgerufen oder zurückgegeben werden.

Damit ein C-Compiler beim Umgang mit einem solchen erweiterten Speicher die richtigen CPU-Anweisungen generiert, wurden die nicht standardmäßigen Schlüsselwörter near und far erfunden. Nichtstandardisiert wie in ihnen werden sie nicht durch den C-Standard spezifiziert, aber sie sind de facto Industriestandard, und fast jeder Compiler unterstützt sie in gewisser Weise.

far bezieht sich auf Speicher, der sich im Erweiterungsspeicher befindet und über die Breite des Adressbusses hinausgeht. Da es sich auf Adressen bezieht, wird es meistens verwendet, wenn Zeiger deklariert werden. Zum Beispiel: int * far x; bedeutet "gib mir einen Zeiger, der auf Erweiterungsspeicher verweist". Der Compiler weiß dann, dass er die speziellen Anweisungen erzeugen muss, die für den Zugriff auf diesen Speicher erforderlich sind. In ähnlicher Weise erzeugen Funktionszeiger, die far verwenden, spezielle Anweisungen, um in den Erweiterungsspeicher zu springen bzw. von diesem zurückzukehren. Wenn Sie nicht far verwendet haben, erhalten Sie einen Zeiger auf den normalen, adressierbaren Speicher, und Sie zeigen auf etwas völlig anderes.

near ist hauptsächlich für die Konsistenz mit far enthalten. es bezieht sich auf alles im adressierbaren Speicher, da es einem regulären Zeiger entspricht. Daher handelt es sich hauptsächlich um ein unbrauchbares Schlüsselwort, außer in seltenen Fällen, in denen Sie sicherstellen möchten, dass der Code im adressierbaren Standardspeicher abgelegt wird. Sie könnten dann etwas explizit als near bezeichnen. Der typischste Fall ist die Low-Level-Hardware-Programmierung, in der Sie Interrupt-Service-Routinen schreiben. Sie werden hardwaremäßig aus einem Interrupt-Vektor mit fester Breite aufgerufen, der der Adressbusbreite entspricht. Das bedeutet, dass sich die Interrupt-Service-Routine im adressierbaren Standardspeicher befinden muss.


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

Diese Schlüsselwörter existieren jedoch auch auf moderneren CPUs! Dies gilt vor allem für eingebettete Systeme, bei denen sie für fast jede 8- und 16-Bit-Mikrocontrollerfamilie auf dem Markt verfügbar sind, da diese Mikrocontroller normalerweise eine Adressbusbreite von 16 Bit haben, jedoch manchmal mehr als 64 KB Speicher.Wann immer Sie über eine CPU verfügen, bei der Sie Speicher außerhalb der Adressbusbreite ansprechen müssen, benötigen Sie 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, warum es einen Push gab, um den 64-Bit-PC zu entwickeln, war tatsächlich, dass die 32-Bit-PCs an den Punkt gekommen waren, an dem ihre Speicherauslastung das Adressbuslimit erreichte: Sie konnten nur 4 GB RAM adressieren. 2 ^ 32 = 4,29 Milliarden Bytes = 4 GB. Um die Verwendung von mehr RAM zu ermöglichen, bestand die Möglichkeit, entweder wie in den DOS-Tagen auf eine lästige erweiterte Speicherlösung zurückzugreifen, oder die Computer einschließlich ihres Adressbusses auf 64 Bit zu erweitern. 

One of the main reasons why there was a Push to develop the 64 bit PC, was actually that the 32 bit PCs had come to the point where their memory usage was starting to hit the address bus limit: they could only address 4Gb of RAM. 2^32 = 4,29 billion bytes = 4Gb. In order to enable the use of more RAM, the options were then either to resort to some burdensome extended memory solution like in the DOS days, or to expand the computers, including their address bus, to 64 bits.

32
Lundin

In alten Plattformen wie DOS wurden weit und nahe Zeiger verwendet.

Ich glaube nicht, dass sie auf modernen Plattformen relevant sind. Aber Sie können über sie hier und hier (wie in anderen Antworten gezeigt) erfahren. Grundsätzlich ist ein far - Zeiger eine Möglichkeit, den adressierbaren Speicher eines Computers zu erweitern. I.E., adressieren Sie mehr als 64 KB Speicher in einer 16-Bit-Plattform.

22

Ein Zeiger enthält im Wesentlichen Adressen. Wie wir alle wissen, ist die Speicherverwaltung von Intel in 4 Segmente unterteilt ..__ Wenn sich also eine Adresse, auf die ein Zeiger zeigt, im selben Segment befindet, handelt es sich um einen Near-Pointer. Daher sind nur 2 Byte für den Offset erforderlich. Wenn dagegen ein Zeiger auf eine Adresse zeigt, die sich außerhalb des Segments befindet (dh in einem anderen Segment), dann ist dieser Zeiger ein Weitzeiger. Es besteht aus 4 Bytes: zwei für Segment und zwei für Offset.

4

Vier Register werden verwendet, um sich auf vier Segmente in der x86-segmentierten x86-Speicherarchitektur zu beziehen. DS (Datensegment), CS (Codesegment), SS (Stapelsegment) und ES (zusätzliches Segment). Eine logische Adresse auf dieser Plattform wird als Segment geschrieben: Offset in Hexadezimal.

Nahe Zeiger beziehen sich (als Versatz) auf das aktuelle Segment.

Fernzeiger verwenden Segmentinformationen und einen Versatz, um über Segmente hinweg zu zeigen. Um sie verwenden zu können, muss DS oder CS auf den angegebenen Wert geändert werden, der Speicher wird dereferenziert und der ursprüngliche Wert von DS/CS wird wiederhergestellt. Beachten Sie, dass die Zeigerarithmetik für sie nicht den Segmentabschnitt des Zeigers ändert. Wenn Sie also den Offset überschreiten, wird er nur umbrochen.

Und dann gibt es riesige Zeiger, die normalisiert werden, um das höchstmögliche Segment für eine gegebene Adresse zu haben (im Gegensatz zu weiten Zeigern).

Bei 32-Bit- und 64-Bit-Architekturen verwenden Speichermodelle Segmente unterschiedlich oder überhaupt nicht.

0
dharam raj

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

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

Seit win nt4 (als sie Ideen von * nix stahlen), begannen Microsoft-Programmierer, sogenannte User/Kernel-Speicherplätze zu verwenden. Und seitdem keinen direkten Zugriff auf physische Steuerungen. Seitdem wurde ein Problem gelöst, das sich auch mit dem direkten Zugriff auf Speichersegmente befasste. - Alles wurde R/W durch OS.

Wenn Sie jedoch auf das Verstehen und Manipulieren von Fern/Nah-Zeigern bestehen, schauen Sie sich die Quelle des Linux-Kernels an und wie es funktioniert - Sie werden, glaube ich, neuere zurückkommen.

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

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

Ich möchte unten auf die perfekte Antwort hinweisen .. von Lundin. Ich war zu faul um richtig zu antworten. Lundin gab eine sehr detaillierte und sinnvolle Erklärung "Daumen hoch"!

0
Oskars Lusis