1
votes

Qu'est-ce que cela signifie exactement en C?

#define RegisterX_Address (*((volatile unsigned int*)0x400253FC))
I need to understand what this (*((volatile unsigned int*)0x400253FC)) in C, I understands that is a pointer pointing to the address of one of the registers but why is it written like this???

0 commentaires

4 Réponses :


0
votes

C'est écrit comme ça parce que c'est ce qui fonctionne sur les compilateurs particuliers utilisés avec ce microcontrôleur particulier. Très probablement, le volatile sert d'indication au compilateur qu'il ne devrait pas faire des optimisations qui auraient pour conséquence de ne pas lire réellement le registre matériel.


2 commentaires

@old_timer Le mot-clé volatile est générique C. Mais le fait qu'il fasse tout ce qui est spécifique à la plate-forme est nécessaire pour lire à partir de ce registre matériel est spécifique à la plate-forme.


le langage est générique C l'adresse spécifique est bien sûr spécifique à un microcontrôleur non spécifié, la question implique qu'il pose des questions sur le langage C et non sur le registre / l'adresse.



3
votes

Quelle que soit la plate-forme, l'adresse mémoire 0x400253FC contient 1 int de données.

Si vous déréférencer 0x400253FC , vous obtenez cette valeur.

Ceci est probablement utilisé pour quelque chose comme:

unsigned int GetCPUTemperature()
{
    unsigned int temp;
    temp = RegisterX_Address;
    return temp;
}

Il n'est pas très courant d'avoir des données mappées directement à une adresse mémoire spécifique, mais se produit régulièrement dans le développement intégré.

Le mot-clé volatile indique au compilateur qu'il ne peut pas mettre en cache, stocker ou réutiliser la valeur qu'il obtient. Il doit récupérer la valeur de la mémoire à chaque accès, car tout ce qui y écrit des données mettra à jour la valeur régulièrement et en dehors de la portée du programme.


4 commentaires

Puisque vous avez modifié la question d'origine, êtes-vous sûr que cela signifie que l'opérateur de déréférence fait partie de la définition? Cela rendrait le suffixe _Address très déroutant.


Suggérer "1 int. De données". -> 1 valeur non signée de données.


@Osiris, l'opérateur de déréférencement était dans la question d'origine. Il était simplement interprété par l'interface utilisateur en mode italique , au lieu d'un littéral *. J'ai ajouté un caractère d'échappement `\` pour clarifier. Je pense que c'était une modification correcte, mais je ne peux pas être sûr à 100%.


@abelenky Oh je vois maintenant, je suppose que c'est vraiment juste un nom déroutant.



1
votes

C'est une macro pour accéder à une broche d'E / S (probablement) mappée en mémoire.

Le compilateur ou le matériel lui-même sait que des adresses de mémoire spécifiques ont un but supplémentaire. Lorsque votre code source lit à partir de ce registre, il lit vraiment la valeur d'une broche d'entrée, un fil connecté directement au processeur. Cette adresse est spéciale, et ce genre de choses est généralement exclusivement lié à ce matériel particulier. (C'est pourquoi vous avez besoin d'une carte shmorgas de différents pilotes pour différents matériels et ils ne sont pas tous facilement interchangeables). Pour toute la mauvaise direction et la généralisation qu'effectuent les niveaux supérieurs, à un moment donné, vous devez diriger la lecture et l'écriture vers le matériel réel avec des adresses réelles.

Le * interne le déclare comme un pointeur. Le * externe est en train de le déréférencer. Et oui, les pointeurs en C sont l'une des parties les plus déroutantes du langage. Le symbole * a vraiment deux tâches; l'un est lors des déclarations, où il décrit un morceau de données. Et le cast explicitement est la déclaration: (volatile unsigned int *) . Cela force le compilateur à traiter la valeur hexadécimale comme un pointeur vers un entier non signé volatil. La seconde, en exécution lors de l'utilisation de cette macro: * (myPointer) , ce pointeur est déréférencé, donc plutôt que d'utiliser la valeur 0x400253FC , vous regardez les données qui vit à ADDRESS 0x400253FC en mémoire. Ce qui n'est même pas de la mémoire car il est probablement mappé sur HW. (Cela dépend. De toute façon, cela s'appelle toujours un registre dans les ICD. Je pense aux registres comme aux registres spécifiques sur la puce, quel assemblage peut utiliser directement par opposition à passer par la MMU. Mais tout est un "registre" pour les gars de HW , ils l'utilisent comme nous utilisons "adresse").

Et je suppose que c'est une broche d'E / S car elle est volatile. C'est une instruction au compilateur de ne pas faire de présomptions lors de l'optimisation, car sa valeur peut changer derrière elle. Comme quand le matériel reçoit un signal. Ou lorsqu'une ligne de sortie se réinitialise automatiquement au niveau bas. Les variables volatiles sont également utilisées pour la mémoire partagée entre les threads, mais sur un microcontrôleur, il s'agit généralement d'E / S.


0 commentaires

0
votes

Essayez-le ...

volatile unsigned int *RegisterX_Address;
RegisterX_Address = (volatile unsigned int *)0x400253FC;
return(*RegisterX_Address);

donne

00000000 <fun>:
   0:   4b01        ldr r3, [pc, #4]    ; (8 <fun+0x8>)
   2:   6818        ldr r0, [r3, #0]
   4:   4770        bx  lr

   8:   400253fc

C'est plus simple à écrire que

#define RegisterX_Address (*((volatile unsigned int*)0x400253FC))
unsigned int fun ( void )
{
    return(RegisterX_Address);
}

C'est pourquoi il est écrit de cette façon. De plus, tel qu'il est écrit, il ne consomme pas de mémoire en tant que variable.


0 commentaires