La règle principale régissant les objets volatile
est la suivante, tirée du C11 6.7.3/7:
selon les règles de la machine abstraite, telles que décrites dans 5.1.2.3. De plus, à chaque point de séquence, la valeur stockée en dernier dans l'objet doit être conforme à celle prescrite par la machine abstraite, sauf si modifiée par les facteurs inconnus mentionnés précédemment.
Et cela continue en disant que
Ce qui constitue un accès à un objet de type volatile est défini par l'implémentation.
, ce qui s'applique à la manière dont d'autres règles (par exemple dans 5.1.2.3) doivent être interprétées. Le guide de l'utilisateur de votre compilateur discute des détails des accès volatils, mais il ne semble pas y avoir de surprise là-bas. La section 5.1.2.3 parle principalement des règles de séquençage; les règles d'évaluation des expressions se trouvent ailleurs (mais doivent toujours être suivies telles quelles en ce qui concerne les accès à votre objet volatile).
Voici les détails pertinents du comportement de la machine abstraite:
-
l'opération d'assignation a pour effet secondaire de stocker une valeur dans l'objet identifié par status
. Il y a un point de séquence à la fin de cette instruction, donc
- l'effet secondaire est appliqué avant que toute évaluation apparaissant dans les instructions suivantes ne soit effectuée, et
- comme
status
est volatile, l'assignation exprimée par cette ligne est la dernière écriture dans status
effectuée par le programme avant le point de séquence.
-
l'expression conditionnelle dans l'instruction if
est évaluée ensuite, avec
- la sous-expression
(status) == (SUCCESS_CONST)
étant évaluée en premier, avant toute autre sous-expression.
- L'évaluation de
status
se fait avant l'évaluation de l'opération ==
, et
- sous forme de conversion de cet identifiant en la valeur stockée dans l'objet qu'il identifie (conversion en lvalue, selon paragraphe 6.3.2.1/2).
- Pour faire quelque chose avec la valeur stockée dans
status
à ce moment-là, cette valeur doit d'abord être lue.
La norme n'exige pas qu'un objet volatile réside dans un stockage adressable, donc en principe, votre variable automatique volatile pourrait être assignée exclusivement à un registre. Dans ce cas, tant que les instructions machine utilisant cet objet lisent directement sa valeur à partir de son registre ou effectuent directement des mises à jour dans son registre, aucun chargement ou stockage distincts ne seraient nécessaires pour obtenir des sémantiques volatiles appropriées. Cependant, votre objet particulier ne semble pas entrer dans cette catégorie, car l'instruction de stockage dans votre assembleur généré semble indiquer qu'elle est en effet associée à un emplacement en mémoire.
De plus, si le programme implémente correctement les sémantiques volatiles pour un objet assigné à un registre, alors ce registre devrait être r0. Je ne suis pas familier avec les spécificités de ce langage d'assemblage et du processeur sur lequel s'exécute le code, mais il ne semble certainement pas que r0 soit un locus viable pour un tel stockage.
Dans ce cas, je suis d'accord sur le fait que status
aurait dû être relu en mémoire, et il doit être relu en mémoire encore une fois si sa deuxième apparition dans l'expression conditionnelle doit être évaluée. C'est le comportement de la machine abstraite, que les implémentations conformes démontrent en ce qui concerne tous les accès volatils. Mon analyse est donc que votre implémentation est non conforme à cet égard, et je serais enclin à signaler cela comme un bug.
Quant à une solution de contournement, je pense que votre meilleur choix serait d'écrire les parties importantes en langage d'assemblage - en langage d'assemblage en ligne si votre implémentation le prend en charge, ou en tant que fonction complète implémentée en langage d'assemblage si nécessaire.