为什么std::cout将易失性指针转换为bool?

发布于 2024-08-27 00:28:51 字数 617 浏览 14 评论 0原文

如果你尝试cout一个指向易失性类型的指针,即使是一个易失性字符指针,你通常希望cout打印字符串,你只会得到'1'(假设指针不为空,我认为)。我假设输出流运算符<<模板是专门用于易失性指针的,但我的问题是,为什么?什么用例激发了这种行为?

示例代码:

#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

If you try to cout a pointer to a volatile type, even a volatile char pointer where you would normally expect cout to print the string, you will instead simply get '1' (assuming the pointer is not null I think). I assume output stream operator<< is template specialized for volatile pointers, but my question is, why? What use case motivates this behavior?

Example code:

#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;
}

Output:

Hello world
1
0x8046b6c
1

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

ヅ她的身影、若隐若现 2024-09-03 00:28:51

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

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

当传入 易失性指针时,无法应用第二个重载,因为易失性指针不能无需显式强制转换即可转换为非易失性。然而,任何指针都可以转换为 bool,所以选择第一个重载,你看到的结果是 1 或 0。

所以真正的原因并不是代表标准委员会的有意决定,而只是标准不指定采用易失性指针的重载。


2023 年更新

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

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

在 C++23 模式下编译时(如果您的编译器支持它),易失性指针现在按照您的预期进行格式化,而不是隐式转换为 布尔

Up through the C++20 standard, ostream::operator<< has the following overloads, among others:

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

When you pass in a volatile pointer, the second overload can't apply because volatile pointers cannot be converted to non-volatile without an explicit cast. However, any pointer can be converted to bool, so the first overload is chosen, and the result you see is 1 or 0.

So the real reason for this is not an intentional decision on behalf of the standards committee, but simply that the standard does not specify an overload that takes a volatile pointer.


2023 Update

Beginning with the C++23 standard (draft N4944, cppreference), ostream::operator<< adds the following overload:

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

When compiling in C++23 mode (if your compiler supports it), volatile pointers are now formatted as you'd expect, instead of being implicitly converted to bool.

2024-09-03 00:28:51

我认为原因是易失性指针不能隐式转换为void *。这是标准的附录 C,其基本原理是类型安全。

更改:仅指向非常量和
非易失性对象可能是隐式的
转换为 void* 理由:这
提高类型安全性。

因此,您不会转换为 void *(将以十六进制打印),而是得到“默认”转换为 bool。

I think the reason is that volatile pointers cannot be converted implicitly to void *. This is in Appendix C of the Standard, and the rationale is type safety.

Change: Only pointers to non-const and
non-volatile objects may be implicitly
converted to void* Rationale: This
improves type safety.

So instead of the conversion to void * (which would print in hex), you get the "default" conversion to bool.

遥远的绿洲 2024-09-03 00:28:51

我认为问题不是指向易失性类型的指针的显式重载,而是指向易失性类型的指针缺乏重载。编译器无法隐式地从指针中删除 volatile 限定符,因此它会检查可用的重载,选择运算符 << 的 bool 版本。并将易失性指针转换为布尔值。

I think the problem is not an explicit overload for pointers to volatile types, but a LACK of overload for pointers to volatile types. The compiler can't implicitly remove the volatile qualifier from the pointers so it checks available overloads, picks the bool version of operator<< and converts the pointer-to-volatile to bool.

两仪 2024-09-03 00:28:51

不是答案

这只是问题和答案的措辞问题。出现问题的原因是无法将指向易失性对象的指针转换为void指针,而不是易失性指针

相当重要的区别在于哪个内存元素是易失性的。在问题中,指针不是易失性的(它可以被缓存,并且在更改时不必刷新到内存),而是指向的内存:

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指向的值,该值是易失性并且会一直到达主内存,而操作[4]只影响指针,它本身不是易失性的,因此不是 C++ 内存模型可感知状态的一部分,并且可以在寄存器中执行(请注意,编译器可以优化 q 并执行寄存器中的操作,而p无法优化。

Not an answer

This is just an issue with the wording of the question and the answers. The problem arises due to the inability to convert pointers to volatile objects into void pointers, not volatile pointers.

The difference, which is rather important, is what memory element is the one that is volatile. In the question, the pointer is not volatile (it can be cached, and it does not have to be flushed to memory when it is changed), but rather the pointed memory:

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

The reason why it is important is that with a volatile pointer to memory, the pointer itself is the one that has special treatment.

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

In the code above, the operations marked as 1 and 2 make it all the way to memory. The assignment in [1] must be dumped to memory. Even if the value of p is in a register, it will be loaded from memory at [2]. The operation marked [3] modifies the value pointed by q which is volatile and will make all the way to main memory, while the operation [4] only affects the pointer, which is not volatile itself, and as such is not part of the c++ memory model perceivable state and can be performed in registers (note that a compiler can optimize away q and perform the operations in a register, while p cannot be optimized.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文