Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Volatile related error in C++ code

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.

like image 503
AnArrayOfFunctions Avatar asked Nov 01 '22 14:11

AnArrayOfFunctions


1 Answers

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 of E1 is “cq1 vq1 X”, and the type of E2 is “cq2 vq2 T”, the expression designates the named member of the object designated by the first expression. If E1 is an lvalue, then E1.E2 is an lvalue; if E1 is an xvalue, then E1.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 is volatile, then vq12 is volatile. Similarly, let the notation cq12 stand for the “union” of cq1 and cq2 ; that is, if cq1 or cq2 is const, then cq12 is const. If E2 is declared to be a mutable member, then the type of E1.E2 is “vq12 T”. If E2 is not declared to be a mutable member, then the type of E1.E2 is “cq12 vq12 T.

vq1 is volatile and vq2 is empty. Thus vq12 is volatile. Thus the type of the expression is volatile T, which is lThreadInfo* volatile.

like image 181
Columbo Avatar answered Nov 15 '22 05:11

Columbo