2009-11-24 5 views
6

Désolé si c'est simple, mon C++ est rouillé.un peu bizarre C++ code

Qu'est-ce que c'est? Il n'y a pas d'appel d'affectation ou de fonction autant que je peux voir. Ce modèle de code est répété plusieurs fois dans un code dont j'ai hérité. Si c'est important, c'est du code intégré.

*(volatile UINT16 *)&someVar->something; 

edit: à partir de là, est ce que le code supplémentaire suivant confirme les suspicions de Heaths? (Exactement à partir du code, y compris la répétition, à l'exception des noms ont été changés pour protéger les innocents)

if (!WaitForNotBusy(50)) 
    return ERROR_CODE_X; 

*(volatile UINT16 *)& someVar->something; 

if (!WaitForNotBusy(50)) 
    return ERROR_CODE_X; 

*(volatile UINT16 *)& someVar->something; 
x = SomeData; 
+1

Code intégré? Alors c'est probablement une adresse physique, comme suspecté. –

+0

Note J'avais ajouté un lien vers l'article dans la réponse ci-dessous: http://www.mjmwired.net/kernel/Documentation/volatile-considered-harmful.txt – Artyom

+0

C'est une bonne idée de lancer le résultat d'une lecture qui ne va nulle part avec '(void)', pour éviter les avertissements du compilateur. Donc '(void) * (volatile uint16_t *) & someVar-> quelque chose'. Bien sûr, envelopper dans une fonction macro ou en ligne, ne pas couper et coller tout cela partout! –

Répondre

19

Il s'agit d'un idiome assez commun dans la programmation intégrée (bien qu'il devrait être encapsulé dans un ensemble de fonctions ou de macros) où un registre de périphérique doit être accédé. Dans de nombreuses architectures, les registres de périphériques sont mappés à une adresse mémoire et sont accessibles comme n'importe quelle autre variable (bien qu'à une adresse fixe - des pointeurs peuvent être utilisés ou l'éditeur de liens peut aider à corriger l'adresse).Cependant, si le compilateur C ne voit pas d'effet secondaire sur un accès à une variable, il peut l'optimiser - à moins que la variable (ou le pointeur utilisé pour accéder à la variable) ne soit marquée comme volatile.

Donc l'expression;

*(volatile UINT16 *)&someVar->something; 

émettra un 16 bits lu à un certain décalage (fournies par le décalage de l'élément de structure something) à partir de l'adresse mémorisée dans le pointeur someVar. Cette lecture se produira et ne pourra pas être optimisée par le compilateur en raison du mot-clé volatile.

Notez que certains registres de périphériques exécutent certaines fonctionnalités même s'ils sont simplement lus - même si les données lues ne sont pas utilisées autrement. Ceci est assez commun avec les registres d'état, où une condition d'erreur peut être effacée après la lecture du registre qui indique l'état d'erreur dans un bit particulier.

Ceci est probablement l'une des raisons les plus courantes de l'utilisation du mot-clé volatile.

+0

Merci, a marqué celui-ci comme réponse parce que je pense que c'est la réponse la plus claire et la plus complète. –

9

Je pense que l'intention de l'auteur était de provoquer le compilateur émette barrières de mémoire à ces points. En évaluant le résultat d'expression d'un volatil, l'indication au compilateur est que cette expression ne doit pas être optimisée, et devrait 'instancier' la sémantique d'accès à un emplacement volatile (barrières de mémoire, restrictions d'optimisations) à chaque ligne où cet idiome se produit.

Ce type d'idiome pourrait être "encapsulé" dans une macro de pré-processeur (#define) au cas où une autre compilation aurait une manière différente de provoquer le même effet. Par exemple, un compilateur ayant la capacité d'encoder directement des barrières de mémoire en lecture ou en écriture pourrait utiliser le mécanisme intégré plutôt que cet idiome. L'implémentation de ce type de code dans une macro permet de changer la méthode dans toute votre base de code.

EDIT: sharth utilisateur a un point que si ce code fonctionne dans un environnement où l'adresse du pointeur est un physique plutôt que adresse virtuelle (ou une adresse virtuelle mappé à une adresse physique spécifique), alors l'exécution de cette opération de lecture peut provoquer une action sur un périphérique.

+2

En outre une macro pourrait rendre plus évident ce qui se passe ... (#define READ_MEMORY_BARRIER ...) – Aaron

+1

La première étape devrait être d'évaluer si elle crée effectivement une barrière de mémoire. Cela semble être l'intention, mais les variables volatiles sur de nombreuses plateformes ne sont ordonnées que par rapport à d'autres variables volatiles. Même si cela fonctionne pour cette plate-forme intégrée, il peut ne pas fonctionner pour un autre; Je chercherais une meilleure solution plus portable pour créer des barrières. –

+1

Je ne pense pas que cela ait quelque chose à voir avec les barrières de la mémoire, c'est une plate-forme intégrée, et elle mappe probablement une variable à certaines E/S. –

9

Alors, voici un long plan.

Si cette adresse pointe vers une zone mappée en mémoire sur un FPGA ou un autre périphérique, alors le périphérique peut réellement faire quelque chose lorsque vous lisez cette adresse.

+0

Pourquoi un tir long? Je pense que c'est une explication parfaitement logique. +1 –

+0

La question originale manquait de beaucoup de clarifications qui indiquent clairement que cela se passe sur un système embarqué, etc. –

-1

Généralement, il s'agit d'un mauvais code.

En C et en C++, le terme "volatile" signifie très peu et ne fournit pas de barrière de mémoire implicite. Donc, ce code est tout à fait faux uness il est écrit comme

memory_barrier(); 
*(volatile UINT16 *)&someVar->something; 

C'est juste un mauvais code.

Expansion:volatile ne fait pas de variable atomique!

Reed cet article: http://www.mjmwired.net/kernel/Documentation/volatile-considered-harmful.txt

C'est pourquoi volatile devrait presque jamais être utilisé dans le code approprié.

+2

Eh! Qu'est-ce que ça veut dire? – Clifford