指针可以变化吗?

时间:2015-10-22 12:18:35

标签: c++ pointers volatile

请考虑以下代码:

int square(volatile int *p)
{
    return *p * *p;
}

现在,volatile关键字表示a中的值 内存位置可以以编译器未知的方式更改或具有 其他未知的副作用(例如通过信号中断修改, 硬件寄存器,或内存映射I / O)即使没有 程序代码修改内容。

那么当我们将指针声明为volatile时会发生什么?

上述代码是否始终有效,或者与此有何不同:

int square(volatile int *p)
{
    int a = *p;
    int b = *p
    return a*b;
}

我们可以最终乘以不同的数字,因为指针是易变的吗?

或者有更好的方法吗?

6 个答案:

答案 0 :(得分:11)

是的,您当然可以使用易失性指针。

易失性意味着不多于且不少于对易失性对象(无论何种类型)的每次访问都被视为可见的副作用,因此免于优化(特别是,这意味着访问可能不会被重新排序)或完全折叠或优化)。这对于读取或写入值,调用成员函数以及当然也用于解除引用也是如此。

请注意,当前一段说明"重新排序"时,假定单个执行线程。易失性不能替代原子操作或互斥锁/锁。

更简单的说法是,volatile通常会转换为“不要优化”,就像我说的那样#34;。

指针的上下文中,请参阅Chris Lattner所熟知的示例性使用模式"每个程序员需要了解的有关未定义行为的信息" article(是的,那篇文章是关于C,而不是C ++,但同样适用):

  

如果您正在使用基于LLVM的编译器,则可以取消引用" volatile" null指针,如果你正在寻找的话,会发生崩溃,因为优化器通常不会触及易失性加载和存储。

答案 1 :(得分:11)

  

指针可以是volatile吗?

绝对;任何类型,不包括函数和引用,可以volatile - 限定。

请注意,易失性指针声明为 T *volatile ,而不是volatile T*,而是声明指针 -volatile < /强>

易失性指针意味着指针值(即其地址而不是指向的值)可能具有编译器在访问时不可见的副作用;因此,对于那些访问,可能不会考虑源自“as-if规则”的优化。

  

int square(volatile int *p) { return *p * *p; }

编译器不能假设读取*p获取相同的值,因此不允许在变量中缓存其值。如你所说,结果可能会有所不同,而不是*p的平方。

具体示例:假设您有两个int s

数组
int a1 [] = { 1, 2, 3, 4, 5 };
int a2 [] = { 5453, -231, -454123, 7565, -11111 };

和指向其中一个的指针

int * /*volatile*/ p = a1;

对尖头元素进行一些操作

for (int i = 0; i < sizeof(a1)/sizeof(a1[0]); ++i) 
       *(p + i) *= 2;

这里p必须在每次迭代时读取volatile,因为它可能实际上由于外部事件而指向a2

答案 2 :(得分:2)

是。 int * volatile

在C ++中,根据类型/指针/引用的关键字在令牌之后,如int * const是指向整数的常量指针,int const *是指向常量整数的指针,int const * const是常量指针到常数整数等只有当第一个标记符号为const int x时,您才可以在类型之前编写关键字。

答案 3 :(得分:2)

volatile关键字是编译器(7.1.6.1/7)的提示:

  

注意:   挥发物   是对实现的暗示,以避免涉及对象的激进优化   因为对象的值可能会被实现无法检测的方式更改。此外,   对于某些实现,   挥发物   可能表示需要访问特殊硬件指令   物体。看到    1.9    详细的语义。一般来说,语义   挥发物   本打算是   同样在C中   ++   因为他们在C.    - 结束说明   ]

这是什么意思?好吧,看看这段代码:

bool condition = false;
while(!condition)
{
    ...
}

默认情况下,编译器将轻松优化条件(它不会更改,因此无需在每次迭代时检查它)。但是,如果您将条件声明为volatile,则不会进行优化。

所以当然你可以有一个易失性指针,并且可以编写因此而崩溃的代码,但变量是volative的事实并不意味着它必然会是因外部干扰而改变。

答案 4 :(得分:1)

您可能最终会将不同的数字相乘,因为它不稳定且可能会意外更改。所以,你可以尝试这样的事情:

int square(volatile int *p)
{
int a = *p;
return a*a;
}

答案 5 :(得分:1)

是的,如果指针变量指向的变量可能会意外地发生变化,即使这可能发生的变化在代码中也不明显,指针也可能是易失性的。

一个示例是一个对象,可以通过控制线程外部的东西进行修改,并且编译器不应该进行优化。

最有可能使用volatile说明符的地方是低级代码,它直接处理硬件以及可能发生意外更改的位置。