volatile struct = struct not possible, why?
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:
- don't make volatile to non-volatile conversions;
- define a suited copy constructor or copy the object members "manually";
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;
}
Volatile Struct Semantics
In your example, the two are the same. But the issues revolve around pointers.
First off, volatile uint8_t *foo;
tells the compiler the memory being pointed to is volatile. If you want to mark the pointer itself as volatile, you would need to do uint8_t * volatile foo;
And that is where you get to the main differences between marking the struct as volatile vs marking individual fields. If you had:
typedef struct
{
uint8_t *field;
} foo;
volatile foo f;
That would act like:
typedef struct
{
uint8_t * volatile field;
} foo;
and not like:
typedef struct
{
volatile uint8_t *field;
} foo;
Does making a struct volatile make all its members volatile?
Another question can be asked (or simply another way to look at the original question):
Does making a struct const
make all its members const
?
If I have:
struct whatever { int data; };
const whatever test;
Will test.data be const
too?
My answer is : Yes. If you declare an object of type whatever
with const
then all its members will be const
too
Similarly, if you declare an object of type whatever
with volatile
then all its members will be volatile
too, just like if you declare the object with const
, all it's member will be const
too.
const
and volatile
are two faces of the same coin; they're so that the Standard often refers to them as cv-qualifiers
.
Quoting from the Standard ($7.1.5.1/8)
[Note: volatile is a hint to the
implementation to avoid aggressive
optimization involving the object
because the value of the object might
be changed by means undetectable by an
implementation. See 1.9 for detailed
semantics. In general, the semantics
of volatile are intended to be the
same in C + + as they are in C. ]
That means, if your object is an instance of a struct, then the compiler cannot avoid aggressive optimization involving the object, unless it avoids aggressive optimization of each of it's members. (Otherwise, how else it can avoid optimization involving the object?)
Related topic:
Why do we use volatile keyword in C++?
indexing an element from a volatile struct doesn't work in C++
Your program is trying to copy a SensorData_t
object. The compiler supplies a copy constructor with the following signature:
SensorData_t(const SensorData_t &)
This copy constructor will not work with volatile
arguments, hence the compilation error.
You can write your own copy constructor which works with volatile
SensorData_t
objects (as well as non-volatile
SensorData_t
objects):
struct SensorData_t {
SensorData_t() = default;
SensorData_t(const volatile SensorData_t &other)
: test(other.test) {
}
int test;
};
Passing a pointer to a struct with a volatile member as a function argument
Short answer: No need to add volatile on hdlPtr.
Long Answer: Unless the hdlPtr can be changed in some unexpected way, there is no need to declare it volatile. Given that it's being local to the function, it can not be changed by anything other than the uartInitialize. Given that you declared it 'const', it can not be changes by the uartInitialize itself.
How can I make a volatile struct behave exactly like a volatile int during assignment?
Your initial problem is because the implicit assignment operator has signature
Bar& operator=(const Bar& rhs);
... and that isn't callable for a volatile
object. The warnings are because your updated function returns a volatile reference, but that reference is never used. GCC thinks that this might be a problem. The simplest way to fix this is to change the return type to void!
There is another problem: Your function will call itself in an infinite recursion. I suggest the following:
struct Bar {
int a;
Bar& operator=(const Bar&rhs) = default;
void operator=(const volatile Bar& rhs) volatile // Note void return.
{
// Caution: This const_cast removes the volatile from
// the reference. This may lose the point of the original
// volatile qualification.
//
// If this is a problem, use "a = rhs.a;" instead - but this
// obviously doesn't generalize so well.
const_cast<Bar&>(*this) = const_cast<const Bar&>(rhs);
}
};
volatile Bar vbar;
Bar bar;
int main(){
vbar = bar; // All four combinations work.
bar = vbar;
vbar = vbar;
bar = bar;
return 0;
}
This means you won't be able to chain assignment operators when using volatile structs. I assert this is not a huge loss.
Final aside: Why are you using volatile
- it's not very useful for multi-threaded code (it is useful for memory mapped IO).
In C, how do you declare the members of a structure as volatile?
Exactly the same as non-struct
fields:
#include <stdio.h>
int main (int c, char *v[]) {
struct _a {
int a1;
volatile int a2;
int a3;
} a;
a.a1 = 1;
a.a2 = 2;
a.a3 = 3;
return 0;
}
You can mark the entire struct
as volatile by using "volatile struct _a {...}"
but the method above is for individual fields.
Related Topics
Linux, Need Accurate Program Timing. Scheduler Wake Up Program
How to Know If Std::Map Insert Succeeded or Failed
Cross-Platform C++: Use The Native String Encoding or Standardise Across Platforms
How to Check If a File Is Still Being Written
Difference Between Dbus and Other Interprocess Communications Method
Rvalue Reference Parameters and Template Functions
How to Query Vsync Phase in Linux
Setting File Permissions When Opening a File with Ofstream
Dynamically Loading Static Library
Priority of Kernel Modules and Sched_Rr Threads
Pass by Reference More Expensive Than Pass by Value
Interactive Console Programming for C/C++
Getting Errors While Compiling
Impact of Hundreds of Idle Threads
Most Efficient Replacement for Isbadreadptr