web-dev-qa-db-fra.com

struct volatile = struct impossible, pourquoi?

struct FOO{
    int a;
    int b;
    int c;
};

volatile struct FOO foo;

int main(void)
{
    foo.a = 10;
    foo.b = 10;
    foo.c = 10;
    struct FOO test = foo;

    return 0;
}

Cela ne se compilera pas, car struct FOO test = foo; génère une erreur:

erreur: la référence de liaison du type 'const FOO &' à 'volatile FOO' supprime les qualificatifs

Comment puis-je copier un volatile struct dans un autre struct en C++ (avant C++ 11)?

Beaucoup de gens ont suggéré de supprimer simplement volatile, mais je ne peux pas le faire dans ce cas, car je veux copier les paramètres SPI-Reg actuels dans un µC et cela est déclaré volatile par les en-têtes du fabricant. Je veux copier ces paramètres, car le fabricant fournit également une bibliothèque pour utiliser le SPI pour EnDat-Communication, et je n'ai pas accès au code source. Puisque je dois changer les paramètres SPI-Reg pendant l'exécution Je veux revenir facilement aux paramètres SPI de la bibliothèque sans appeler à nouveau init_endat () - lib fkt (ce n'est pas spécifié ce qui se passe si je l'appelle deux fois).

Puis-je éventuellement utiliser memcopy () pour cela?

Comme suggéré, ceci est une copie de la question suivante.

Pourquoi ne suis-je pas fourni avec un constructeur de copie par défaut à partir d'un volatile?

23
makum

Ceci est mal formé car FOO a un constructeur de copie implicite défini comme:

FOO(FOO const&);

Et vous écrivez FOO test = foo; avec foo de type volatile FOO, en invoquant:

FOO(volatile FOO const&);

Mais les références à la conversion implicite références à volatiles à références à non volatiles sont mal formées.

De là, deux solutions émergent:

  1. ne faites pas de conversions volatiles en non volatiles;
  2. définir un constructeur de copie adapté ou copier les membres de l'objet "manuellement";
  3. const_cast peut supprimer le qualificatif volatile, mais il s'agit d'un comportement indéfini à utiliser si votre objet sous-jacent est effectivement volatil.

Puis-je éventuellement utiliser memcopy () pour cela?

Non, vous ne pouvez pas, memcpy est incompatible avec les objets volatils: il n'y a pas de surcharge qui prend des pointeurs à volatile, et il n'y a rien que vous puissiez faire sans invoquer un comportement indéfini.

Donc, en conclusion, votre meilleur coup si vous ne pouvez pas ajouter un constructeur à FOO est de définir:

FOO FOO_copy(FOO volatile const& other)
{
    FOO result;
    result.a = other.a;
    result.b = other.b;
    result.c = other.c;
    return result;
}

Ou avec C++ 11 std::tie :

FOO FOO_copy(FOO volatile const& other)
{
    FOO result;
    std::tie(result.a, result.b, result.c) = std::tie(other.a, other.b, other.c);
    return result;
}
23
YSC

Pour donner une autre approche à une réponse, pour expliquer pourquoi cela n'a pas de sens, plutôt que simplement où la norme C++ dit que cela n'est pas valide:

L'intérêt de volatile est que vous avez un contrôle précis sur quelle variable est accessible quand. Cela signifie que volatile int i, j;, i = 1; j = 2; et j = 2; i = 1; ne fait pas la même chose. Le compilateur ne peut pas transformer librement l'un en l'autre. La même chose s'applique aux lectures: étant donné volatile int i, j; int x, y;, x = i; y = j; et y = j; x = i; ne fait pas la même chose. La présence de volatile signifie que les accès must se produisent dans exactement dans l'ordre que vous avez spécifié.

Maintenant, dans votre exemple, que devrait struct FOO test = foo; faire? Vous n'avez jamais spécifié si vous souhaitez d'abord lire foo.a, puis foo.b, enfin foo.c, ou peut-être lire d'abord foo.c, puis foo.b, enfin foo.a, ou peut-être un autre ordre.

Vous pouvez, si vous le souhaitez, faire ceci:

struct FOO test;
test.a = foo.a;
test.b = foo.b;
test.c = foo.c;

Ici, vous spécifiez explicitement l'ordre des accès aux champs de foo, afin d'éviter le problème.

19
user743382

Vous n'avez pas fourni suffisamment de détails sur votre problème pour donner une évaluation plus précise, mais la solution à tout problème que vous essayez de résoudre est presque certainement de ne pas utiliser volatile. "Volatile" signifie que la valeur peut changer sous vos pieds: les deux cas d'utilisation typiques sont des variables modifiées à partir des gestionnaires de signaux UNIX et des registres mappés en mémoire. La volatilité n'est pas suffisante pour les variables partagées entre les threads, notamment.

La raison pour laquelle vous obtenez cette erreur est que votre compilateur essaie de trouver un constructeur de copie FOO(volatile FOO&), qui n'est jamais généré automatiquement.

3
zneak