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

This won't compile, because struct FOO test = foo; generates an error:

error: binding reference of type 'const FOO&' to 'volatile FOO' discards qualifiers

How can I copy a volatile struct into another struct in C++ (before C++11)?

Many people suggested to just delelte volatile, but I can't do that in that case, because I want to copy the current SPI-Reg setttings inside a µC and this is declared volatile by the manufacturer headers. I want to copy those settings, because the manufactuerer also provides an Library to use the SPI for EnDat-Communication, and I don't have access to the source-code. Since I have to change the SPI-Reg-Settings during runtime I want to easyly get back to the library SPI-settings without calling the init_endat()-lib fkt again (it's unspecified what happens if i call it twice).

Could I possibly use memcopy() for that?

As suggested, this is a copy of the following question.

Why am I not provided with a default copy constructor from a volatile?

7
  • 13
    Perhaps the first question is what do you want volatile for? (hint: you probably don't) Commented Mar 19, 2018 at 16:29
  • Which compiler gives you this error ? Also, using "volatile" is useful when clearing memory that contains some sensitive data (e.g. encryption keys) even if no code reads this memory after clearing. See: stackoverflow.com/questions/49084430/…. Commented Mar 20, 2018 at 1:50
  • I think memcpy will suffer from the same error. Perhaps copying it memberwise is the only option. Commented Mar 20, 2018 at 6:53
  • Possible duplicate (sort of) stackoverflow.com/questions/17217300/… Commented Mar 20, 2018 at 6:59
  • 2
    I literally came here trying to find an answer to a similar question, working on embedded development, using volatile to interact with memory mapped hardware. And the first thing I see is @JiveDadson being a condescending prick telling the OP he's clearly wrong for using volatile. This site is a cesspool. Commented Jul 9, 2023 at 23:42

3 Answers 3

24

This is ill-formed because FOO has an implicit copy constructor defined as:

FOO(FOO const&);

And you write FOO test = foo; with foo of type volatile FOO, invoking:

FOO(volatile FOO const&);

But references-to-volatile to references-to-non-volatile implicit conversion is ill-formed.

From here, two solutions emerge:

  1. don't make volatile to non-volatile conversions;
  2. define a suited copy constructor or copy the object members "manually";
  3. const_cast can remove the volatile qualifier, but this is undefined behavior to use that if your underlying object is effectively volatile.

Could I possibly use memcopy() for that?

No you cannot, memcpy is incompatible with volatile objects: thre is no overload of it which takes pointers-to-volatile, and there is nothing you can do without invoking undefined behavior.

So, as a conclusion, your best shot if you cannot add a constructor to FOO is to define:

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

Or with C++11's 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;
}
Sign up to request clarification or add additional context in comments.

7 Comments

You omitted the only correct answer: 0. Remove volatile.
@JiveDadson it's kinda included in 1. ;) though, volatile might be really needed in OP's context, we don't know. But we know from OP's profile page they are an embedded software engineer, so...
I guess it's possible. I had a use for volatile about 23 years ago. It can happen.
You say "two solutions", then provide a list of three items. I think the list item shouldn't be part of the list (since it's not a solution).
@TobySpeight that's the joke. Its funny because the list does actually contain exactly two solutions, is it not?
|
22

To give another approach to an answer, to address why this doesn't make sense, rather than just where the C++ standard says this is invalid:

The whole point of volatile is that you have precise control over which variable gets accessed when. That means given volatile int i, j;, i = 1; j = 2; and j = 2; i = 1; do not do the same thing. The compiler cannot freely transform one into the other. The same applies to reads: given volatile int i, j; int x, y;, x = i; y = j; and y = j; x = i; do not do the same thing. The presence of volatile means the accesses must happen in exactly the order you specified.

Now, in your example, what should struct FOO test = foo; do? You've never specified whether you want to first read foo.a, then foo.b, finally foo.c, or perhaps first read foo.c, then foo.b, finally foo.a, or perhaps some other order.

You can, if you wish, do this:

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

Here, you explicitly specify the order of the accesses to foo's fields, so you avoid the problem.

8 Comments

I like this approach.
That's not what volatile means. That's what std::atomic with memory order std::memory_order_seq_cst means. Visual C++ makes some memory order guarantees for volatile unless you set a standard-compliance flag, but the promises are not that strong. volatile is for accessing memory-mapped hardware only and I guess UNIX signal handlers.
@JiveDadson You're reading more into my answer than what I actually wrote. What I wrote is exactly what volatile means. Per [intro.execution]p8.1: "Access to volatile objects are evaluated strictly according to the rules of the abstract machine."
@hvd volatile guarantees individual accesses will not be optimized away, but does not prevent them from being reordered with others (that is, volatile in C++ does not establish happens-before order).
I like how volatile is sooo mystical for some developers :) @JAB you know how the compiler is allowed to reorder instruction following the "as-if" rule? Well this rule does not apply for volatile objects (see [intro.execution]/8.1 quoted above). What you are talking about is related to multi-threaded programs, and yes in this context volatile does not help. hvd's answer is about in-thread instruction order.
|
2

You haven't provided enough details about your problem to give a more precise assessment, but the solution to whatever problem you're trying to solve is almost certainly not to use volatile. "Volatile" means that the value can change from under your feet: the two typical good use cases are variables changed from within UNIX signal handlers and memory-mapped registers. Volatile is not enough for variables shared among threads, notably.

The reason you are getting this error is that your compiler is trying to find a FOO(volatile FOO&) copy constructor, which is never automatically generated.

1 Comment

The other use case of volatile is for variables that are used in the presence of setjmp and longjmp. Which I would caution against using without a very, very good reason.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.