什么是* volatile * name = value?

时间:2014-01-11 17:44:05

标签: c++ volatile

我在c ++语法中偶然发现了一些非常奇怪的东西。 volatile *类型。

这是我找到的代码(在Qt库中):

void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
{
if (receiver == 0) {
    qWarning(""QCoreApplication::postEvent: Unexpected null receiver"");
    delete event;
    return;
}

QThreadData * volatile * pdata = &receiver->d_func()->threadData; 
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ WHAT IS THIS???
QThreadData *data = *pdata;
if (!data) {
    // posting during destruction? just delete the event to prevent a leak
    delete event;
    return;
}

// [...]
}

我理解的是:

  • 我不能写volatile * QThreadData * pdata,因为那时我会遇到编译错误。这显然是因为对象不能是volatile *,而是指针可以。
  • pdata不是QThreadData *,而是QThreadData * volatile *类型。在尝试编译此代码时:int * volatile * x = new int(10);我会得到以下编译器错误:“无法在初始化中将'int *'转换为'int * volatile *'

所以这些是我的问题:

  • 类型QThreadData * volatile *是什么类型volatile *是什么意思?
  • 为什么volatile *类型的一部分。为什么QThreadData *类型不具有volatile *属性?

2 个答案:

答案 0 :(得分:6)

声明QThreadData * volatile * pdata表示pdata是指向QThreadData的易失性指针的指针。

通常,volatile表示对象可以以超出编译器控件的方式进行更改。例如,如果它存储在由其他硬件写入的内存中。这意味着编译器必须在每次需要时从内存中读取值,而不是假设如果它之前已经读过该值并且它没有对该内存位置进行更改,那么该值仍然是同样的。

所以在这种情况下,pdata本身并不易变。这意味着允许编译器假设pdata不会意外地更改。但是,pdata指向的内容可以意外地改变,它指向的是另一个指针。此外,其他易失性指针所指向的内容(实际的QThreadData)本身并不易变。

在C ++中,constvolatile的处理方式非常相似。它们都表明该对象具有一些特殊属性。通过要求将这些特性与类型一起携带,可以更容易地避免某些错误。这对于const更容易看到,但同样的逻辑适用于volatile。例如

void f(int *p)
{
    *p += 2;
    *p += 3;
}

int main()
{
    volatile int a = 5;
    f(&a); // error: can't convert volatile int * to int *
}

由于函数f是与函数main分开编译的,编译器在编译函数f时不会知道它不应该假设*p意外地未发生变化。没有这方面的知识,它可能会有效地改变代码

*p += 5;

但这是错误的,因为* p可能会在两次添加之间发生变化。

答案 1 :(得分:6)

为了帮助解决您的困惑,您首先要知道的是您有双指针类型

接下来要说的是volatile - ness是类型const的一部分 - ness是类型的一部分:这个事实被称为 cv-qualification

  

[C++11: 7.1.6.1/7]: [注意: volatile是对实现的暗示,以避免涉及对象的激进优化,因为对象的值可能会被无法通过实现。有关详细语义,请参见1.9。通常,volatile的语义在C ++中应该与它们相同   在C. _ - 尾注] _

短语volatile *不是任何一个特定的东西:它是类型中的两个标记,可能意味着许多事情。


在这种情况下,您有一个QThreadData* volatile*,它是“指向QThreadData”类型的易失性指针的指针。从右到左阅读。

如果您将volatile删除,则会留下QThreadData**


如果你想要一个更简单的例子,这里有两个:

int volatile x = 5;
volatile int y = 6;

请参阅const,这里我们可以稍微使用 cv-qualifier 的顺序,因为没有歧义。

让我们稍微提升一下这个例子:

int volatile* p = new int volatile(5);

现在我们有一个指向int volatile的指针(再次,与volatile int相同)。 volatile适用于左病房;也就是说,int,而不是*

但我们也可能有一个易变的指针!比方说,指向非易失性int的易失性指针:

int* volatile p = new int(5);

我不知道你所说的“财产”是什么意思。