C pointeurs et adresse physique

Je viens juste de commencer C. J’ai lu des ouvrages sur des pointeurs dans divers livres / tutoriels et je comprends les bases. Mais une chose que je n’ai pas vu expliquer, c’est quels sont les chiffres.

Par exemple:

int main(){ int anumber = 10; int *apointer; apointer = &anumber; printf("%i", &apointer); } 

peut renvoyer un nombre tel que 4231168. Que représente ce nombre? Est-ce une désignation de stockage dans la RAM?

Beaucoup de programmeur PC répond comme toujours. Voici une réponse d’un sharepoint vue de la programmation générique.

Vous serez très intéressé par la valeur numérique réelle de l’adresse lors de toute forme de programmation liée au matériel. Par exemple, vous pouvez accéder aux registres du matériel d’un ordinateur de la manière suivante:

 #define MY_REGISTER (*(volatile unsigned char*)0x1234) 

Ce code suppose que vous sachiez qu’il existe un registre matériel spécifique situé à l’adresse 0x1234. Toutes les adresses d’un ordinateur sont, par tradition / pour des raisons de commodité, exprimées au format hexadécimal.

Dans cet exemple, l’adresse a une longueur de 16 bits, ce qui signifie que le bus d’adresse de l’ordinateur utilisé a une largeur de 16 bits. Chaque cellule de mémoire de votre ordinateur a une adresse. Ainsi, sur un bus d’adresse 16 bits, vous pouvez avoir un maximum de 2 ^ 16 = 65 536 cellules de mémoire adressables. Sur un PC, par exemple, l’adresse a une longueur de 32 bits, ce qui vous donne 4,29 milliards de cellules de mémoire adressables, soit 4,29 gigaoctets.

Pour expliquer cette macro en détail:

  • 0x1234 est l’adresse du registre / de l’emplacement mémoire.
  • Nous devons accéder à cet emplacement mémoire via un pointeur. Par conséquent, nous convertissons la constante de nombre entier 0x1234 en pointeur de caractère non signé = un pointeur sur un octet.
  • Cela suppose que le registre qui nous intéresse a une taille de 1 octet. Si la taille avait été de deux octets, nous aurions peut-être utilisé non signé short.
  • Les registres de matériel peuvent se mettre à jour à tout moment (leur contenu est “volatil”), de sorte que le programme ne peut émettre aucune hypothèse / optimisation de ce qui y est stocké. Le programme doit lire la valeur du registre à chaque fois que le registre est utilisé dans le code. Pour appliquer ce comportement, nous utilisons le mot clé volatile.
  • Enfin, nous voulons accéder au registre comme s’il s’agissait d’une variable simple. Par conséquent, le * est ajouté pour prendre le contenu du pointeur.

Le programme peut maintenant accéder à l’emplacement de mémoire spécifique:

 MY_REGISTER = 1; unsigned char var = MY_REGISTER; 

Par exemple, un code comme celui-ci est utilisé partout dans les applications intégrées.

(Mais comme déjà mentionné dans d’autres réponses, vous ne pouvez pas faire ce genre de chose sur les PC modernes, car ils utilisent ce que l’on appelle un adressage virtuel, ce qui vous donne une tape sur les doigts si vous le tentez.)

C’est l’adresse ou l’emplacement de la mémoire à laquelle se réfère le pointeur. Toutefois, si vous considérez cela comme une quantité opaque, il est préférable de ne jamais vous intéresser à la valeur réelle du pointeur, mais uniquement à celle à laquelle il se rapporte.

La relation entre l’adresse et la mémoire physique est un service fourni par le système et varie réellement entre les systèmes.

C’est une adresse virtuelle d’ anumber variable. Chaque programme a son propre espace mémoire et cet espace est mappé sur la mémoire physique. Le mappage effectué par le processeur et les données de service utilisées à cet effet sont conservés par le système d’exploitation. Donc, votre programme ne sait jamais où il se trouve dans la mémoire physique.

C’est l’adresse de l’emplacement de la mémoire 1 où votre variable est stockée. Ne vous souciez pas de la valeur exacte, sachez simplement que différentes variables ont des adresses différentes, que la “mémoire contiguë” (par exemple, les tableaux) a des adresses contiguës, …

En passant, pour imprimer l’adresse stockée dans un pointeur, vous devez utiliser le spécificateur %p dans printf .


  1. Notez que je n’ai pas dit «RAM», car dans la plupart des systèmes d’exploitation modernes, la «mémoire» que votre processus considère comme étant une mémoire virtuelle, c’est-à-dire une abstraction de la RAM réelle gérée par le système d’exploitation.

Beaucoup de gens vous ont dit que la valeur numérique d’un pointeur désignera son adresse. C’est un moyen par lequel les implémentations peuvent le faire, mais c’est très important, ce que dit la norme C à propos des pointeurs:

  • Le pointeur nil a toujours la valeur numérique 0 lorsqu’il est utilisé dans le langage de programmation C. Toutefois, la mémoire contenant le pointeur peut avoir une valeur quelconque, à condition que cette valeur spéciale dépendante de l’architecture soit systématiquement traitée comme étant nulle et que la mise en oeuvre veille à ce que cette valeur soit vue comme 0 par le code source C. Il est important de le savoir, car 0 pointeurs peuvent apparaître comme une valeur différente sur certaines architectures lorsqu’ils sont inspectés avec un débogueur de mémoire de bas niveau.
  • Il n’y a aucune exigence que les valeurs du pointeur soient liées de quelque manière que ce soit aux adresses réelles. Ce peuvent être aussi des identifiants abstraits, résolus par une table de conversion ou similaire.
  • Si un pointeur adresse un tableau, les règles d’arithmétique de pointeur doivent être respectées, c’est-à-dire int array[128]; int a, b; a = (int)&array[120]; b = (int)&array[100]; a - b == 20 ; array + (ab) == &array[20]; &array[120] == (int*)a int array[128]; int a, b; a = (int)&array[120]; b = (int)&array[100]; a - b == 20 ; array + (ab) == &array[20]; &array[120] == (int*)a
  • L’arithmétique de pointeur entre les pointeurs vers différents objects n’est pas définie et provoque un comportement non défini.
  • Le pointeur de mappage sur l’entier doit être réversible. En d’autres termes, si un nombre correspond à un pointeur valide, la conversion en ce pointeur doit être valide. Toutefois, l’arithmétique (pointeur) sur la représentation numérique des pointeurs vers différents objects n’est pas définie.

Oui, c’est exactement cela: c’est l’adresse des données d’un pointeur en mémoire. Les variables locales telles que anumber et un pointeur seront allouées dans la stack de votre programme, ainsi il fera référence à une adresse dans le cadre de la fonction main () dans la stack.

Si vous aviez alloué la mémoire avec malloc () à la place, il ferait référence à une position dans l’espace de tas de votre programme. S’il s’agissait d’une chaîne fixe, elle pourrait faire référence à un emplacement dans les segments de données ou rodata (données en lecture seule) de votre programme.

dans ce cas, & apointer représente l’adresse en mémoire RAM de la variable de pointeur apointer

apointer est “l’adresse” de la variable anumber . En théorie, il pourrait s’agir de l’emplacement physique réel dans la RAM où la valeur d’un anumber est stockée, mais en réalité (sur la plupart des systèmes d’exploitation), il s’agit probablement d’un emplacement dans la mémoire virtuelle. Le résultat est le même si.

C’est une adresse mémoire, très probablement à l’emplacement actuel dans la stack de votre programme. Contrairement au commentaire de David, il arrive que vous calculiez des décalages de pointeur, mais uniquement si vous traitez une sorte de tableau.

C’est l’adresse du pointeur.

“anumber” prend un peu de place dans la RAM, les données à cet endroit contiennent le nombre 10.

“apointer” prend également un peu de place dans la RAM, les données à cet endroit contiennent l’emplacement de “anumber” dans la RAM.

Donc, disons que vous avez 32 octets de RAM, adresses 0..31

Par exemple, à la position 16, vous avez 4 octets, la valeur “anumber” 10

Par exemple, à la position 20, vous avez 4 octets, le “pointeur”, la valeur 16, la position “un numéro” dans la RAM.

Ce que vous imprimez est 20, la position du pointeur dans la RAM.

Notez que ce n’est pas vraiment directement dans la RAM, mais dans l’espace d’adressage virtuel mappé sur la RAM. Afin de comprendre les pointeurs, vous pouvez complètement ignorer l’espace d’adressage virtuel.

Ce n’est pas l’adresse de la variable anumber qui est imprimée, mais l’adresse du pointeur qui est imprimé.