【问题标题】:Volatile related error in C++ codeC++ 代码中的易失性相关错误
【发布时间】:2015-01-13 01:58:19
【问题描述】:

你能帮我理解为什么编译器会给我这些错误信息吗?我相信 volatile 对象的成员也是 volatile 。我指的是here。但它表明,如果我们有一个结构:

struct someStruct
{
    int d;
};

而“p”的定义如下:

volatile someStruct* volatile* p;

&(*p)->d 具有以下类型 'int* volatile*' 而不是 'volatile int* volatile*'。下面是我正在处理的实际代码。


这些行(标有错误 1 ​​和 2)是编译器抛出错误消息的地方:

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

错误消息如下:

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

注意:我知道 volatile 与线程安全无关,所以不要告诉我。注意1:我在 windows 上使用 mingw64 编译器。

【问题讨论】:

  • 对于第二个错误,您将需要一个 const_cast 来摆脱 Windows API 函数调用的 volatile。对于第一个错误,成员 pNextList 也需要为 volatile(或从 p 中删除 volatile)。
  • 但是创建一个带有 volatile 说明符的对象不应该自动使它的所有子对象也 volatile 吗?
  • lThreadInfo::pNextList 的类型为 lThreadInfo*。如果您有一个 lThreadInfo 对象,即 volatile,例如lThreadInfo volatile o;,那么o.pNextList 就是lThreadInfo* volatile。 cv 限定符总是应用于“最外层”的类型,而不是指向的类型。
  • 那么我怎样才能存储一个指向这个子对象的指针,我可以用它来修改它,就像它来自 volatile 类型一样。

标签: c++ windows c++11 gcc volatile


【解决方案1】:

pNextList,通过volatile 访问路径,也是volatile。但是pNextList指针pointee 类型具有与以前相同的 cv-qualification。

也就是说,对于

struct A
{
    lThreadInfo* p;
};

someStruct volatile* volatile* p;
  • *psomeStruct volatile* volatile 类型的左值
  • (*p)-&gt;dlThreadInfo* volatile 类型的左值。

所以在(*p)-&gt;d 类型中,您缺少lThreadInfo* 之间的易失性。 [expr.ref]/4:

如果E2是一个非静态数据成员并且E1的类型是“cq1 vq1 X”,而E2的类型是“cq2 vq2 T”,表达式 指定第一个指定的对象的命名成员 表达。如果E1 是一个左值,那么E1.E2 是一个左值;如果E1 是一个极值,那么E1.E2 是一个极值;否则,它是一个prvalue。 让符号vq12代表vq1vq2的“并集”;也就是说,如果 vq1vq2volatile,那么 vq12volatile 类似地,让符号 cq12 代表 cq1cq2 的“并集” ;也就是说,如果 cq1cq2const,那么 cq12 就是const。如果 E2 被声明为可变的 成员,则E1.E2 的类型为“vq12 T”。如果E2 不是 声明为可变成员,则E1.E2 的类型为“cq12 vq12 T.

vq1volatilevq2 为空。因此 vq12volatile。因此表达式的类型为volatile T,即lThreadInfo* volatile

【讨论】:

    猜你喜欢
    • 2012-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 2019-08-31
    • 1970-01-01
    相关资源
    最近更新 更多