Quelqu'un peut-il me dire la différence entre les pointeurs far
et near
en C?
Sur une architecture de mémoire segmentée x86 16 bits, quatre registres sont utilisés pour faire référence aux segments respectifs:
Une adresse logique sur cette architecture est écrite segment:offset
. Maintenant pour répondre à la question:
Les pointeurs proches se réfèrent (sous forme de décalage) au segment en cours.
Les pointeurs éloignés utilisent les informations de segment et un décalage pour pointer les segments. Ainsi, pour les utiliser, vous devez modifier DS ou CS à la valeur spécifiée, la mémoire sera déréférencée, puis la valeur d'origine de DS/CS restaurée. Notez que l'arithmétique de pointeur sur eux ne modifie pas la partie segmentée du pointeur, donc le dépassement du décalage ne fera que l'enrouler.
Et puis, il y a d’énormes pointeurs, normalisés pour avoir le segment le plus élevé possible pour une adresse donnée (contrairement aux pointeurs de loin).
Sur les architectures 32 bits et 64 bits, les modèles de mémoire utilisent les segments différemment, voire pas du tout.
Puisque personne n’a mentionné le DOS, oublions les vieux ordinateurs sous DOS et examinons-le d’un point de vue générique. Alors, très simplifié, ça se passe comme ça:
Toute CPU a un bus de données, qui est la quantité maximale de données que la CPU peut traiter en une seule instruction, c'est-à-dire égale à la taille de ses registres. La largeur du bus de données est exprimée en bits: 8 bits, ou 16 bits, ou 64 bits, etc. L’origine du terme "CPU 64 bits" vient du mot "bus de données".
Toute CPU a un bus d’adresse, également avec une certaine largeur de bus exprimée en bits. Toute cellule de mémoire de votre ordinateur à laquelle le processeur peut accéder directement a une adresse unique. Le bus d’adresses est assez grand pour couvrir toute la mémoire adressable que vous avez.
Par exemple, si un ordinateur dispose de 65 536 octets de mémoire adressable, vous pouvez les couvrir avec un bus d’adresse 16 bits, 2 ^ 16 = 65536.
Le plus souvent, mais pas toujours, la largeur du bus de données est aussi large que celle du bus d’adresse. C'est bien si elles ont la même taille, car cela permet de clarifier le jeu d'instructions de la CPU et les programmes qui y sont écrits. Si le processeur doit calculer une adresse, il est pratique si cette adresse est suffisamment petite pour tenir dans les registres du processeur (souvent appelés registres d'index lorsqu'il s'agit d'adresses).
Les mots-clés non-standard far
et near
sont utilisés pour décrire les pointeurs sur les systèmes où vous devez adresser de la mémoire au-delà de la largeur de bus de l'adresse CPU normale.
Par exemple, il peut être pratique pour une CPU avec bus de données 16 bits de disposer également d’un bus d’adresse 16 bits. Mais un même ordinateur peut également nécessiter plus de 2 ^ 16 = 65 536 octets = 64 Ko de mémoire adressable.
Le processeur aura alors généralement des instructions spéciales (légèrement plus lentes) qui lui permettront d’adresser de la mémoire au-delà de ces 64 ko. Par exemple, le processeur peut diviser sa grande mémoire en n
pages (aussi parfois appelée banks, segments et autres termes du même type, qui pourraient avoir une signification différente d'un processeur à l'autre), où chaque page est 64kb. Il aura alors un registre "page" qui doit être réglé avant d’adresser cette mémoire étendue. De même, il aura des instructions spéciales pour appeler/revenir de sous-routines en mémoire étendue.
Pour qu'un compilateur C génère les instructions correctes de l'UC lorsqu'il traite avec une telle mémoire étendue, les mots-clés near
et far
non standard ont été inventés. Non standard car ils ne sont pas spécifiés par le standard C, mais ils sont de facto des standards de l'industrie et presque tous les compilateurs les prennent en charge d'une manière ou d'une autre.
far
fait référence à la mémoire située dans la mémoire étendue, au-delà de la largeur du bus d'adresses. Puisqu'il fait référence à des adresses, vous l'utilisez le plus souvent lors de la déclaration de pointeurs. Par exemple: int * far x;
signifie "donnez-moi un pointeur qui pointe vers la mémoire étendue". Et le compilateur saura alors qu'il devrait générer les instructions spéciales nécessaires pour accéder à cette mémoire. De même, les pointeurs de fonction qui utilisent far
généreront des instructions spéciales pour accéder à/revenir de la mémoire étendue. Si vous n'utilisiez pas far
, vous obtiendrez un pointeur sur la mémoire normale, adressable, et vous vous retrouverez face à quelque chose de complètement différent.
near
est principalement inclus pour des raisons de cohérence avec far
; il fait référence à tout ce qui se trouve dans la mémoire adressable, ce qui équivaut à un pointeur normal. Il s’agit donc principalement d’un mot clé inutile, sauf dans certains cas rares où vous souhaitez vous assurer que le code est placé dans la mémoire adressable standard. Vous pouvez alors explicitement étiqueter quelque chose comme near
. Le cas le plus typique est la programmation matérielle de bas niveau dans laquelle vous écrivez des routines de service d'interruption. Ils sont appelés par le matériel à partir d'un vecteur d'interruption de largeur fixe, identique à la largeur du bus d'adresses. Cela signifie que la routine de service d'interruption doit être dans la mémoire adressable standard.
L’utilisation la plus connue de far
et near
est peut-être l’ancien ordinateur MS DOS mentionné, qui est considéré aujourd’hui comme très ancien et donc d’un faible intérêt.
Mais ces mots-clés existent aussi sur les CPU les plus modernes! En particulier dans les systèmes embarqués où ils existent pour à peu près toutes les familles de microcontrôleurs 8 et 16 bits du marché, car ces microcontrôleurs ont généralement une largeur de bus d'adresses de 16 bits, mais parfois plus de 64 Ko de mémoire.Chaque fois que vous avez un processeur sur lequel vous devez adresser de la mémoire au-delà de la largeur du bus d’adresses, vous aurez besoin de far
et near
. Généralement, de telles solutions sont mal vues, car il est très pénible de les programmer et de toujours prendre en compte la mémoire étendue.
L'une des principales raisons pour lesquelles il existait un Push pour développer le PC 64 bits était en fait que les PC 32 bits étaient arrivés au point où leur utilisation de la mémoire commençait à atteindre la limite du bus d'adresses: ils ne pouvaient traiter que 4 Go de RAM. 2 ^ 32 = 4,29 milliards d'octets = 4 Go. Afin de permettre l'utilisation de plus de RAM, les options étaient alors soit de recourir à une solution de mémoire étendue fastidieuse comme à l'époque du DOS, soit d'étendre les ordinateurs, y compris leur bus d'adresses, à 64 bits.
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.
Les pointeurs lointains et proches étaient utilisés sur les anciennes plates-formes telles que DOS.
Je ne pense pas qu'ils sont pertinents dans les plates-formes modernes. Mais vous pouvez apprendre à leur sujet ici et ici (comme indiqué par d'autres réponses). Fondamentalement, un pointeur far est un moyen d'étendre la mémoire adressable dans un ordinateur. I.E., adresse plus de 64k de mémoire dans une plate-forme 16 bits.
Un pointeur contient essentiellement des adresses. Comme nous le savons tous, la gestion de la mémoire Intel est divisée en 4 segments . Ainsi, lorsqu'une adresse désignée par un pointeur se trouve dans le même segment, il s'agit d'un pointeur proche et ne nécessite donc que 2 octets pour le décalage .En revanche, lorsqu'un pointeur pointe sur une adresse en dehors du segment (c'est-à-dire dans un autre segment), ce pointeur est un pointeur éloigné. Il est composé de 4 octets: deux pour le segment et deux pour le décalage.
Quatre registres sont utilisés pour faire référence à quatre segments de l’architecture de mémoire segmentée x86 16 bits. DS (segment de données), CS (segment de code), SS (segment de pile) et ES (segment supplémentaire). Une adresse logique sur cette plate-forme est écrite segment: offset, en hexadécimal.
Les pointeurs proches se réfèrent (sous forme de décalage) au segment en cours.
Les pointeurs éloignés utilisent les informations de segment et un décalage pour pointer les segments. Ainsi, pour les utiliser, vous devez modifier DS ou CS à la valeur spécifiée, la mémoire sera déréférencée, puis la valeur d'origine de DS/CS restaurée. Notez que l'arithmétique de pointeur sur eux ne modifie pas la partie segmentée du pointeur, donc le dépassement du décalage ne fera que l'enrouler.
Et puis, il y a d’énormes pointeurs, normalisés pour avoir le segment le plus élevé possible pour une adresse donnée (contrairement aux pointeurs de loin).
Sur les architectures 32 bits et 64 bits, les modèles de mémoire utilisent les segments différemment, voire pas du tout.
Eh bien, sous DOS, c’était assez drôle de gérer les registres. Et des segments. Tout sur les capacités de comptage maximum de RAM.
Aujourd'hui, c'est à peu près hors de propos. Tout ce que vous devez lire, c’est la différence entre l’espace virtuel/utilisateur et le noyau.
Depuis win nt4 (quand ils ont volé des idées sur * nix), les programmeurs Microsoft ont commencé à utiliser ce qu’on appelait des espaces mémoire utilisateur/noyau. Et depuis, elle a évité l’accès direct aux contrôleurs physiques. Depuis lors, le problème lié à l'accès direct aux segments de mémoire a été résolu. - Tout est devenu R/W à travers OS.
Cependant, si vous insistez pour comprendre et manipuler les pointeurs lointains/proches, examinez la source du noyau Linux et son fonctionnement - vous aurez l'impression de revenir plus tard, je suppose.
Et si vous devez toujours utiliser CS (segment de code)/DS (segment de données) sous DOS. Regarde-les:
https://en.wikipedia.org/wiki/Intel_Memory_Modelhttp://www.digitalmars.com/ctg/ctgMemoryModel.html
Je voudrais signaler à perfectionner réponse ci-dessous .. de Lundin. J'étais trop paresseux pour répondre correctement. Lundin a donné une explication très détaillée et sensée "bravo"!