0
votes

Conversions entre les types volatils, const, volatils et "ni"

Que dit la norme C ++ (11) sur les conversions entre les types volatile, const, volatile const et "ni"? Je comprends qu'il est bien défini et acceptable d'attribuer un type const à un type non const et non volatile, mais qu'en est-il des conversions entre les types suivants (où T est un type)?

T volatile a;
T const b;

a = b; // implicit conversion from const to volatile; okay?

template<typename T>
void fcn(T& t)
{
    t = b; // implicit conversion from const to non-const, which I assume is okay
}
fcn(a); // implicit conversion from volatile to non-volatile; okay?

À titre d'exemple simple, considérons le code suivant:

// T
T
T volatile
T const 
T volatile const 

// Pointer-to-T
T*
T volatile*
T const*
T volatile const*

// Volatile pointer-to-T
T* volatile
T volatile* volatile
T const* volatile
T volatile const* volatile

// Const pointer-to-T
T* const
T volatile* const
T const* const
T volatile const* const

// Volatile const pointer-to-T
T* volatile const
T volatile* volatile const
T const* volatile const
T volatile const* volatile const


0 commentaires

3 Réponses :


1
votes

Que pouvez-vous attribuer à quoi?

Vous pouvez toujours attribuer des valeurs volatiles à des valeurs non const. Vous pouvez également affecter des valeurs const et non const à des valeurs volatiles. Vous ne pouvez jamais attribuer quoi que ce soit aux valeurs const, car elles sont const.

Une conversion a-t-elle lieu?

Non, il s'agit juste d'un devoir.

Pourquoi?

volatile signifie que tout accès à un objet ne peut pas être optimisé . Il y a en fait très peu de cas où volatile est jamais nécessaire, ou utilisé. Ces cas sont:

  • Lorsque vous chronométrez une opération et que vous ne voulez pas que le calcul soit optimisé (veuillez utiliser une bibliothèque d'analyse comparative pour cela. Ne lancez pas la vôtre)
  • Lorsque vous effectuez des E / S avec mappage de mémoire. Dans ce cas, vous voulez garantir que les lectures et les écritures ne sont pas optimisées, donc volatile peut être utilisé.

Pour cette raison, il doit être possible d'attribuer volatile à des objets normaux et vice versa. Dans le même temps, cependant, les références volatiles ne devraient pas être implicitement converties en références régulières, car cela conduirait potentiellement à l'optimisation des lectures et des écritures.

Qu'en est-il de const?

Vous pouvez assigner des éléments const à n'importe quoi, mais rien ne peut être assigné à const (car c'est const).


3 commentaires

Autres cas pour Volatile : Routines de service d'interruption (ISRS) ou tout autre threads / processus indépendants Un programme donné n'est pas conscient de cela peut toucher une variable (par exemple, application latérale d'hôte qui parle au processeur cible intégré) .


Pour votre exemple d'E / S mappées en mémoire, il semble étrange que la tentative de lecture d'un octet soit optimisée? Comment ça marche?


@JoeManiaci À titre d'exemple, si le registre MMIO est écrit uniquement via "matériel", et uniquement lu depuis le programme (peut-être au-delà de la définition d'une valeur d'initialisation), alors le compilateur pourrait simplement renvoyer une constante ou la valeur initiale du registre à chaque fois au lieu de charger réellement le contenu du registre.



1
votes
a = b; // implicit conversion from const to volatile; okay?

Que ce soit "ok" dépend du type T.

Ce qui se passe ici est une conversion lvalue-en-rvalue. Voici ce que disent les règles standard:

[conv.lval]

Une valeur gl d'un type T sans fonction et sans tableau peut être convertie en une valeur pr. Si T est un type incomplet, un programme qui nécessite cette conversion est mal formé. Si T est un type non-classe, le type de la prvalue est la version cv-non qualifiée de T. Sinon, le type de la prvalue est T.

Donc, si par exemple T n'est pas un type de classe, alors la prvaleur de la conversion de T const b sera un T , qui est le même que le type de la variable affectée dans ce cas. Donc, tant que T est assignable (c'est-à-dire pas const), il est "ok".

Pour les types de classe, si l'affectation est "ok", dépend de quel type d'opérateur (s) d'affectation de la classe. L’opérateur d’affectation implicite n’est pas qualifié de manière volatile. L’exemple d’affectation ne serait donc pas "correct". Ce serait mal formé. Mais il est possible qu'un utilisateur déclare un opérateur d'affectation qualifié volatil, bien que ce soit assez rare.


0 commentaires

0
votes

Concernant fcn (a); // conversion implicite de volatile à non volatile; d'accord? , ce n'est pas bien selon this , car cela aboutira à référencer un type volatil à partir d'un type non volatile:

La norme C, 6.7.3 [ISO / CEI 9899: 2011], déclare

Si une tentative est faite de faire référence à un objet défini avec un type qualifié volatile via l'utilisation d'une lvalue avec un type qualifié non volatile, le comportement est indéfini.


De plus, même si je n'ai pas de référence, je pense que les affectations et les conversions entre les pointeurs doivent avoir le même type qualifié volatile- / const- auquel elles pointent (c'est-à-dire le const s / volatiles avant le * doit correspondre):

T volatile * volatile t; T volatile * volatile const t1 = t; // d'accord; initialisation de const avec non-const T * volatil t2 = t; // pas bien; t et t2 pointent vers différents types T volatile const * volatile t3 = t; // pas bien; t et t3 pointent vers différents types


0 commentaires