Can you help me to understand why the compiler is giving me those error messages? I believe members of volatile objects are volatile too. I'm referring from here. But it shows up that if we have a structure:
struct someStruct
{
int d;
};
And 'p' is a defined like:
volatile someStruct* volatile* p;
&(*p)->d
have the following type 'int* volatile*' instead of 'volatile int* volatile*'. Below is the actual code on which I'm working on.
The lines (marked with error 1 & 2) is where the compiler throws an error messages:
#include <vector>
#include <windows.h>
using namespace std;
struct ThreadInfo
{
bool bWaiting = false;
bool bWorking = false;
};
struct lThreadInfo
{
ThreadInfo d;
lThreadInfo *pNextList = nullptr;
} volatile *volatile lThreads(nullptr);
thread_local ThreadInfo* currentThr(nullptr);
void CreateThread_(void (*pFunc)(ThreadInfo*))
{
volatile lThreadInfo* volatile* p = &lThreads;
for(; *p; p = &(*p)->pNextList); //**//error 1!**
*p = new lThreadInfo;
CreateThread(
nullptr, // default security attributes
0, // use default stack size
(long unsigned int (*)(void*))pFunc, // thread function name
&(*p)->d, // argument to thread function **//error 2!**
0, // use default creation flags
nullptr);
}
The errors messages are the following:
error 1: invalid conversion from 'lThreadInfo* volatile*' to 'volatile lThreadInfo* volatile*' [-fpermissive]
error 2: invalid conversion from 'volatile void*' to 'LPVOID {aka void*}' [-fpermissive]
Note: I know that volatile have nothing to do with thread-safety, so don't bother telling me so.Note1: I'm using mingw64 compiler on windows.
pNextList
, through a volatile
access-path, is volatile
too. But pNextList
is the pointer. The pointee type has the same cv-qualification as before.
That is, for
struct A
{
lThreadInfo* p;
};
someStruct volatile* volatile* p;
*p
is an lvalue of type someStruct volatile* volatile
(*p)->d
is an lvalue of type lThreadInfo* volatile
.So in the type of (*p)->d
you're missing the volatile between lThreadInfo
and *
. [expr.ref]/4:
If
E2
is a non-static data member and the type ofE1
is “cq1 vq1X
”, and the type ofE2
is “cq2 vq2T
”, the expression designates the named member of the object designated by the first expression. IfE1
is an lvalue, thenE1.E2
is an lvalue; ifE1
is an xvalue, thenE1.E2
is an xvalue; otherwise, it is a prvalue. Let the notation vq12 stand for the “union” of vq1 and vq2; that is, if vq1 or vq2 isvolatile
, then vq12 isvolatile
. Similarly, let the notation cq12 stand for the “union” of cq1 and cq2 ; that is, if cq1 or cq2 isconst
, then cq12 isconst
. IfE2
is declared to be a mutable member, then the type ofE1.E2
is “vq12T
”. IfE2
is not declared to be a mutable member, then the type ofE1.E2
is “cq12 vq12T
”.
vq1 is volatile
and vq2 is empty. Thus vq12 is volatile
. Thus the type of the expression is volatile T
, which is lThreadInfo* volatile
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With