指针可以是易变的吗?
Can a pointer be 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;
}
我们最终可以将不同的数字相乘吗,因为指针是易变的?
或者有更好的方法吗?
是的,你当然可以有一个 volatile 指针。
volatile 意味着 none 多 none 小于 volatile 对象(任何类型)上的每次访问都被视为可见的副作用,因此免于优化(在特别是,这意味着访问可能不会被重新排序、折叠或优化)。这对于读取或写入一个值、调用成员函数以及取消引用当然也是如此。
请注意,当上一段说 "reordering" 时,假定 单线程执行 。 volatile 不能替代原子操作或 mutexes/locks.
用更简单的话来说,volatile
通常可以大致翻译为 "Don't optimize, just do exactly as I say"。
在 指针 的上下文中,请参考 Chris Lattner 著名的 "What every programmer needs to know about Undefined Behavior" article 给出的示例性使用模式(是的,那篇文章是关于C,而不是C++,但同样适用):
If you're using an LLVM-based compiler, you can dereference a "volatile" null pointer to get a crash if that's what you're looking for, since volatile loads and stores are generally not touched by the optimizer.
您最终可能会乘以不同的数字,因为它是易变的并且可能会意外更改。所以,你可以尝试这样的事情:
int square(volatile int *p)
{
int a = *p;
return a*a;
}
是的。 int * volatile
.
在C++中,根据type/pointer/reference的关键字在token之后,比如int * const
是指向整数的常量指针,int const *
是指向常量整数的指针,int const * const
是指向常量整数 e.t.c 的常量指针。仅当它是第一个标记时,您才可以在类型之前写关键字:const int x
等于 int const x
.
volatile
关键字是对编译器(7.1.6.1/7)的提示:
Note:
volatile
is a hint to the implementation to avoid aggressive optimization involving the object
because the value of the object might be changed by means undetectable by an implementation. Furthermore,
for some implementations,
volatile
might indicate that special hardware instructions are required to access
the object. See
1.9
for detailed semantics. In general, the semantics of
volatile
are intended to be the
same in C
++
as they are in C.
— end note
]
这是什么意思?好吧,看看这段代码:
bool condition = false;
while(!condition)
{
...
}
默认情况下,编译器会很容易地优化条件(它不会改变,所以不需要在每次迭代时都检查它)。但是,如果您将条件声明为 volatile
,则不会进行优化。
所以你当然可以有一个 volatile 指针,并且有可能编写会因此而崩溃的代码,但是变量是 volative
的事实并不意味着它一定会去由于一些外部干扰而改变。
是的,如果指针指向的变量可以意外更改,则指针可以是可变的,即使从代码中看不出这是如何发生的。
一个例子是一个对象,它可以被控制线程外部的东西修改,编译器不应该优化。
最有可能使用 volatile 说明符的地方是直接处理硬件的低级代码,并且可能会发生意外更改。
Can a pointer be volatile
?
当然;任何类型,不包括函数和引用,都可以是 volatile
限定的。
请注意,volatile 指针被声明为 T *volatile
,而不是 volatile T*
,它声明了一个 pointer-到-volatile.
volatile 指针意味着指针值,即它的地址而不是所指向的值,在访问时可能具有编译器不可见的副作用;因此,这些访问可能不会考虑源自 "as-if rule" 的优化。
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
。
int square(volatile int *p)
{
int a = *p;
int b = *p
return a*b;
}
由于*ptr的值有可能意外改变,a和b有可能不同。因此,此代码可以 return 一个不是正方形的数字!正确的编码方式是:
long square(volatile int *p)
{
int a;
a = *p;
return a * a;
}
考虑以下代码:
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;
}
我们最终可以将不同的数字相乘吗,因为指针是易变的?
或者有更好的方法吗?
是的,你当然可以有一个 volatile 指针。
volatile 意味着 none 多 none 小于 volatile 对象(任何类型)上的每次访问都被视为可见的副作用,因此免于优化(在特别是,这意味着访问可能不会被重新排序、折叠或优化)。这对于读取或写入一个值、调用成员函数以及取消引用当然也是如此。
请注意,当上一段说 "reordering" 时,假定 单线程执行 。 volatile 不能替代原子操作或 mutexes/locks.
用更简单的话来说,volatile
通常可以大致翻译为 "Don't optimize, just do exactly as I say"。
在 指针 的上下文中,请参考 Chris Lattner 著名的 "What every programmer needs to know about Undefined Behavior" article 给出的示例性使用模式(是的,那篇文章是关于C,而不是C++,但同样适用):
If you're using an LLVM-based compiler, you can dereference a "volatile" null pointer to get a crash if that's what you're looking for, since volatile loads and stores are generally not touched by the optimizer.
您最终可能会乘以不同的数字,因为它是易变的并且可能会意外更改。所以,你可以尝试这样的事情:
int square(volatile int *p)
{
int a = *p;
return a*a;
}
是的。 int * volatile
.
在C++中,根据type/pointer/reference的关键字在token之后,比如int * const
是指向整数的常量指针,int const *
是指向常量整数的指针,int const * const
是指向常量整数 e.t.c 的常量指针。仅当它是第一个标记时,您才可以在类型之前写关键字:const int x
等于 int const x
.
volatile
关键字是对编译器(7.1.6.1/7)的提示:
Note: volatile is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation. Furthermore, for some implementations, volatile might indicate that special hardware instructions are required to access the object. See 1.9 for detailed semantics. In general, the semantics of volatile are intended to be the same in C ++ as they are in C. — end note ]
这是什么意思?好吧,看看这段代码:
bool condition = false;
while(!condition)
{
...
}
默认情况下,编译器会很容易地优化条件(它不会改变,所以不需要在每次迭代时都检查它)。但是,如果您将条件声明为 volatile
,则不会进行优化。
所以你当然可以有一个 volatile 指针,并且有可能编写会因此而崩溃的代码,但是变量是 volative
的事实并不意味着它一定会去由于一些外部干扰而改变。
是的,如果指针指向的变量可以意外更改,则指针可以是可变的,即使从代码中看不出这是如何发生的。
一个例子是一个对象,它可以被控制线程外部的东西修改,编译器不应该优化。
最有可能使用 volatile 说明符的地方是直接处理硬件的低级代码,并且可能会发生意外更改。
Can a pointer be
volatile
?
当然;任何类型,不包括函数和引用,都可以是 volatile
限定的。
请注意,volatile 指针被声明为 T *volatile
,而不是 volatile T*
,它声明了一个 pointer-到-volatile.
volatile 指针意味着指针值,即它的地址而不是所指向的值,在访问时可能具有编译器不可见的副作用;因此,这些访问可能不会考虑源自 "as-if rule" 的优化。
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
。
int square(volatile int *p)
{
int a = *p;
int b = *p
return a*b;
}
由于*ptr的值有可能意外改变,a和b有可能不同。因此,此代码可以 return 一个不是正方形的数字!正确的编码方式是:
long square(volatile int *p)
{
int a;
a = *p;
return a * a;
}