web-dev-qa-db-ja.com

volatile struct = structは不可能です、なぜですか?

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;
}

struct FOO test = foo;がエラーを生成するため、これはコンパイルされません。

エラー:タイプ 'const FOO&'から 'volatile FOO'へのバインディング参照は修飾子を破棄します

C++(C++ 11より前)でvolatile structを別のstructにコピーするにはどうすればよいですか?

多くの人々は揮発性を単に削除することを提案しましたが、現在のSPI-Reg設定をµC内にコピーし、これが製造元のヘッダーによって揮発性であると宣言されているため、私はそれを行うことができません。これらの設定をコピーしたいのは、メーカーがSPI for EnDat-Communicationを使用するためのライブラリも提供しており、ソースコードにアクセスできないためです。変更する必要があるので、ランタイム中のSPI-Reg-Settingsは、再度init_endat()-lib fktを呼び出さなくても簡単にライブラリのSPI-settingsに戻したいです(2回呼び出すと何が起こるかは不定です)。

そのためにmemcopy()を使用できますか?

提案されたように、これは次の質問のコピーです。

揮発性からのデフォルトのコピーコンストラクターが提供されないのはなぜですか?

23
makum

FOOには暗黙のコピーコンストラクターが次のように定義されているため、これは不正な形式です。

FOO(FOO const&);

そして、あなたはFOO test = foo; with foo with type volatile FOO、呼び出し:

FOO(volatile FOO const&);

ただし、参照から揮発性への参照から不揮発性への参照への暗黙的な変換は、形式が正しくありません。

ここから、2つの解が現れます:

  1. 揮発性から不揮発性への変換を行わないでください。
  2. 適切なコピーコンストラクターを定義するか、オブジェクトメンバーを「手動」でコピーします。
  3. const_castはvolatile修飾子を削除できますが、これは、基礎となるオブジェクトが実質的に揮発性である場合に使用する未定義の動作です。

そのためにmemcopy()を使用できますか?

いいえ、できません。memcpyはvolatileオブジェクトと互換性がありません。volatileへのポインターを取るオーバーロードはなく、未定義の動作を呼び出さずにできることはありません。

したがって、結論として、FOOにコンストラクターを追加できない場合の最善の方法は、以下を定義することです。

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

または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

答えに別のアプローチを与えるには、C++標準でこれが無効であると述べている場所だけでなく、なぜこれが意味をなさないのかを説明します。

volatileの要点は、いつどの変数にアクセスするかを正確に制御できることです。つまり、volatile int i, j;i = 1; j = 2;j = 2; i = 1;を指定しても、同じことは行われません。コンパイラは、一方を他方に自由に変換することはできません。同じことが読み取りにも当てはまります。指定されたvolatile int i, j; int x, y;x = i; y = j;、およびy = j; x = i;は同じことを行いません。 volatileの存在は、アクセスmustexactlyで発生したことを意味し、指定した順序でアクセスします。

さて、あなたの例では、struct FOO test = foo;は何をすべきですか?最初にfoo.a、次にfoo.b、最後にfoo.c、または最初にfoo.c、次にfoo.b、最後にfoo.a、またはその他の順序のいずれを読み取るかを指定したことはありません。

あなたが望むなら、これを行うことができます:

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

ここでは、fooのフィールドへのアクセス順序を明示的に指定して、問題を回避しています。

19
user743382

より正確な評価を行うために問題について十分な詳細を提供していませんが、解決しようとしている問題の解決策は、ほとんどの場合volatileを使用しないことです。 「揮発性」とは、足元から値が変更される可能性があることを意味します。2つの一般的な優れた使用例は、UNIXシグナルハンドラー内およびメモリマップレジスタ内から変更された変数です。特にスレッド間で共有される変数については、揮発性では不十分です。

このエラーが発生する理由は、コンパイラがFOO(volatile FOO&)コピーコンストラクタを見つけようとしているためです。これは決して自動的に生成されません。

3
zneak