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
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.
So instead of the conversion to void * (which would print in hex), you get the "default" conversion to 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.
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:
The reason why it is important is that with a volatile pointer to memory, the pointer itself is the one that has special treatment.
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 byq
which isvolatile
and will make all the way to main memory, while the operation [4] only affects the pointer, which is notvolatile
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 awayq
and perform the operations in a register, whilep
cannot be optimized.ostream::operator<<
has the following overloads, among others: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 committe, but simply that the standard does not specify an overload that takes a volatile pointer.