2014-11-15 16 views
5

Potete aiutarmi a capire perché il compilatore mi sta dando quei messaggi di errore? Credo che anche i membri di oggetti volatili siano volatili. Mi riferisco a here. Ma si presenta che se abbiamo una struttura:Errore correlato volatile nel codice C++

struct someStruct 
{ 
    int d; 
}; 

E 'p' è un definito come:

volatile someStruct* volatile* p; 

&(*p)->d hanno il seguente tipo 'int * volatili *' invece di 'int volatili * volatile * '. Di seguito è riportato il codice effettivo su cui sto lavorando.


Le linee (contrassegnati con l'errore 1 & 2) è dove il compilatore genera un messaggio di errore:

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

I messaggi di errore sono i seguenti:

error 1: invalid conversion from 'lThreadInfo* volatile*' to 'volatile lThreadInfo* volatile*' [-fpermissive] 
error 2: invalid conversion from 'volatile void*' to 'LPVOID {aka void*}' [-fpermissive] 

Nota: So che volatile non ha nulla a che fare con la sicurezza dei thread, quindi non preoccuparti di dirmelo. Note1: sto usando il compilatore mingw64 su Windows.

+0

Per il secondo errore, è necessario un 'const_cast' per escludere il' volatile' per la chiamata della funzione API di Windows. Per il primo errore, anche il membro 'pNextList' deve essere' volatile' (o rimuovere 'volatile' da' p'). – Niall

+0

Ma la creazione di un oggetto con lo specificatore volatile non dovrebbe rendere automaticamente volatili anche tutti gli oggetti secondari? – AnArrayOfFunctions

+0

'lThreadInfo :: pNextList' ha il tipo' lThreadInfo * '. Se hai un oggetto 'lThreadInfo' che è' volatile', ad es. 'lThreadInfo volatile o;', quindi 'o.pNextList' è' lThreadInfo * volatile'. I qualificatori di cv sono sempre applicati al tipo "più esterno", non al tipo puntato. – dyp

risposta

2

pNextList, tramite un percorso di accesso volatile, è volatile. Ma pNextList è il puntatore . Il tipo pointee ha la stessa qualifica di cv di prima.

Cioè, per

struct A 
{ 
    lThreadInfo* p; 
}; 

someStruct volatile* volatile* p; 
  • *p è un lvalue di tipo someStruct volatile* volatile
  • (*p)->d è un lvalue di tipo lThreadInfo* volatile.

Così nel tipo di (*p)->d ti manca la volatilità tra il lThreadInfo e *. [Expr.ref]/4:

Se E2 è un membro di dati non statico e il tipo di E1 è “CQ1 VQ1 X”, e il tipo di E2 è “CQ2 vq2T ", L'espressione designa il membro nominato dell'oggetto designato dalla prima espressione . Se E1 è un lvalue, allora E1.E2 è un lvalue; se E1 è un valore x, quindi E1.E2 è un valore x; altrimenti, è un valore. Lasciate la notazione vq12 stand per la “unione” di VQ1 e vq2; cioè, se VQ1 o vq2 è volatile, quindi vq12 è volatile. Analogamente, lasciare la notazione cq12 stand per il "sindacato" di cq1 e cq2; cioè, se CQ1 o CQ2 è const, quindi cq12 è const. Se E2 è dichiarato membro muto , il tipo di E1.E2 è "vq12T". Se non E2 è dichiarato essere un membro mutevole, quindi il tipo di E1.E2 è “cq12 vq12T.

VQ1 è volatile e vq2 è vuoto. Pertanto vq12 è volatile. Quindi il tipo dell'espressione è volatile T, che è lThreadInfo* volatile.