指针可以是可变的吗?

新手上路,请多包涵

考虑以下代码:

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

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

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

上面提到的代码是否总是有效,或者与此有什么不同:

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

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

或者有更好的方法吗?

原文由 vishal 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 753
2 个回答

指针可以是 volatile 吗?

绝对地;任何类型,不包括函数和引用,都可能是 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

原文由 edmz 发布,翻译遵循 CC BY-SA 3.0 许可协议

是的,你当然可以有一个 volatile 指针。

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

请注意,当上一段说“重新排序”时,假定 _单个执行线程_。 Volatile 不能替代原子操作或互斥锁/锁。

用更简单的话来说, volatile 通常大致翻译为“不要优化,只是照我说的做”。

指针 的上下文中,请参阅 Chris Lattner 著名的“每个程序员需要了解的关于未定义行为的内容” 文章 给出的示例性使用模式(是的,那篇文章是关于 C,而不是 C++,但同样适用):

如果您使用的是基于 LLVM 的编译器,则可以取消引用“volatile”空指针以获取崩溃(如果这是您要查找的内容),因为优化器通常不会触及 volatile 加载和存储。

原文由 Damon 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏