c++ 为什么std::cout要将volatile指针转换为bool?

bd1hkmkf  于 2023-04-13  发布在  其他
关注(0)|答案(4)|浏览(146)

如果你试图cout一个指向volatile类型的指针,即使是一个volatile char指针,你通常会期望cout打印字符串,你会得到'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
oyt4ldly

oyt4ldly1#

在C++20标准中,ostream::operator<<有以下重载:

ostream& operator<< (bool val );
ostream& operator<< (const void* val );

当传入volatile指针时,第二个重载不能应用,因为volatile指针在没有显式强制转换的情况下无法转换为nonvolatile。然而,任何指针都可以转换为bool,因此选择了第一个重载,您看到的结果是1或0。
因此,真实的的原因并不是代表标准委员会的故意决定,而只是标准没有指定接受volatile指针的重载。

2023更新

从C++23标准(draft N4944cppreference)开始,ostream::operator<<添加了以下重载:

basic_ostream& operator<<( const volatile void* value );

当在C++23模式下编译时(如果你的编译器支持它),volatile指针的格式现在和你期望的一样,而不是隐式地转换为bool

fjaof16o

fjaof16o2#

我认为原因是volatile指针不能隐式转换为void 。这在标准的附录C中,基本原理是类型安全。
更改:只有指向非常量和非易失性对象的指针可以隐式转换为void
理由:这提高了类型安全性。
因此,不是转换为void *(以十六进制打印),而是“默认”转换为bool。

2vuwiymt

2vuwiymt3#

  • 不是答案 *

这只是问题和答案的措辞问题。问题的出现是由于无法将 * 指向volatile* 对象的指针转换为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

它之所以重要,是因为对于指向内存的volatile指针,指针本身是具有特殊处理的指针。

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]只影响指针,它不是volatile本身,因此不是C++存储器模型可感知状态的一部分,并且可以在寄存器中执行(注意,编译器可以优化掉q并在寄存器中执行操作,而p不能被优化。

nzkunb0c

nzkunb0c4#

我认为问题不是指向volatile类型的指针的显式重载,而是指向volatile类型的指针缺少重载。编译器不能隐式地从指针中删除volatile限定符,所以它会检查可用的重载,选择运算符〈〈的bool版本并将指向volatile的指针转换为bool。

相关问题