如果你尝试cout指向volatile类型的指针,即使是你通常希望cout打印字符串的volatile指针,你只需要得到'1'(假设指针不是null我认为)。我假设输出流运算符<<是专门用于volatile指针的模板,但我的问题是,为什么?什么用例激发了这种行为?
示例代码:
#include <iostream>
#include <cstring>
int main()
{
char x[500];
std::strcpy(x, "Hello world");
int y;
int *z = &y;
std::cout << x << std::endl;
std::cout << (char volatile*)x << std::endl;
std::cout << z << std::endl;
std::cout << (int volatile*)z << std::endl;
return 0;
}
输出:
Hello world
1
0x8046b6c
1
答案 0 :(得分:27)
ostream::operator<<
具有以下重载:
ostream& operator<< (bool val );
ostream& operator<< (const void* val );
传入易失性指针时,第二个重载无法应用,因为如果没有显式强制转换,则无法将易失性指针转换为非易失性。但是,任何指针都可以转换为bool,因此选择第一个重载,您看到的结果是1或0.
因此,真正的原因不是代表标准委员会的故意决定,而只是标准没有指定带有易失性指针的重载。
答案 1 :(得分:5)
我认为原因是volatile指针不能隐式转换为void *。这在标准的附录C中,理由是类型安全。
更改:仅指向非const和 非易失性对象可能是隐含的 转换为void *理由:这个 提高类型安全性。
因此,不是转换为void *(将以十六进制打印),而是将“默认”转换为bool。
答案 2 :(得分:2)
不是答案
这只是问题和答案的措辞问题。问题出现的原因是无法将指针转换为易失性对象转换为void指针,而不是 volatile指针。
差异,这是非常重要的,是内存元素是易失性的。在这个问题中,指针不是易失性的(它可以被缓存,并且在更改时不必刷新到内存),而是指向内存:
int volatile * p = f();
p++; // this does not affect the perceived state of the c++ memory model
++p;
*p = 5; // this changes the perceived state
重要的原因是,对于内存的易失性指针,指针本身就是具有特殊处理的指针。
void foo( int * );
int * volatile p = f(); // 1
foo(p); // 2
int volatile * q = f();
//foo(q); // error, cannot convert pointer to volatile to pointer to non-volatile
*q = 5; // 3
q = 0; // 4
在上面的代码中,标记为1和2的操作使其一直到内存。必须将[1]中的赋值转储到内存中。即使p
的值在寄存器中,它也将从[2]的内存中加载。标记为[3]的操作修改q
指向的值volatile
并且将一直到主内存,而操作[4]仅影响指针,而不是{{1本身并不是c ++内存模型可感知状态的一部分,可以在寄存器中执行(注意编译器可以优化volatile
并在寄存器中执行操作,而q
无法优化。
答案 3 :(得分:1)
我认为问题不是针对volatile类型的指针的显式重载,而是针对volatile类型的指针的重载LACK。编译器不能从指针中隐式删除volatile限定符,因此它检查可用的重载,选择bool版本的operator&lt;&lt;并将指针转换为bool。