0

To clear illustrate the problem, here is a minimal code. Why there is no output for my line cout << z << endl;? I am running it on Mac OS, compiler is Apple clang version 12.0.0 (clang-1200.0.32.29) Target: x86_64-apple-darwin20.3.0

#include <iostream>

using namespace std;
int main() {
  int x = 15;
  int *y = &x;
  unsigned char *z = (unsigned char *)&x;
  cout << y << endl; //this line works OK
  cout << z << endl; //no output of this line
  printf("%x", z); // this line works OK
  return 0;
}
drbombe
  • 609
  • 7
  • 15
  • 1
    Because, apparently, with your compiler using `<<` to output a pointer to an unsigned char does not print the pointer's value. The same thing happens as with a pointer to a plain char. – Sam Varshavchik Apr 11 '21 at 14:28
  • Check the different `operator<<` implementations, both the free ones and the ones implemented as member functions of `std::ostream`. BTW: Your code invokes UB by using the result of that C-style, brute-force cast. Don't use them unless you really know you need them. – Ulrich Eckhardt Apr 11 '21 at 14:28
  • @UlrichEckhardt I don't think it's UB per se. `unsigned char` is exempt from strict aliasing. – HolyBlackCat Apr 11 '21 at 14:35
  • Hmmm, that may actually be true, @HolyBlackCat. – Ulrich Eckhardt Apr 11 '21 at 14:38
  • It seems that casting it into void will work. `cout << (void*)z << endl; ` – drbombe Apr 11 '21 at 14:38
  • Still, stop using C-style casts unnecessarily. That said, giving a pointer to `printf()` when the format string expects an integer will give you further issues. Most compilers can actually warn you of this, provided you enable warnings. – Ulrich Eckhardt Apr 11 '21 at 14:40
  • I was working a customized casting method which requires a byte by byte translating. It seems that (unsigned char *) is the only way that I know to operate in byte level. – drbombe Apr 11 '21 at 14:43
  • `operator<<(std::ostream &, const unsigned char *)` interprets the pointer as C string and prints the string not the address. Casting to `void *` is a solution but you should avoid C-style casts. Use `static_cast`. – Thomas Sablik Apr 11 '21 at 15:08
  • Does this answer your question? [cout << with char\* argument prints string, not pointer value](https://stackoverflow.com/questions/17813423/cout-with-char-argument-prints-string-not-pointer-value) – Thomas Sablik Apr 11 '21 at 15:09
  • Thanks! Yes, I think that explains the issue – drbombe Apr 11 '21 at 15:56

1 Answers1

3

operator<< does not have an overload for an int* pointer, so the expression cout << y ends up calling the void* overload, which prints the memory address that the pointer is pointing at. It doesn't try to access the data being pointed at. Same with printf("%x", z).

operator<< does have an overload for an unsigned char* pointer, which treats the pointer as pointing to a null-terminated string, same as the char* overload does. But z is not a pointer to a null-terminated string, so your code has undefined behavior when trying to print z this way. To print the address that z is pointing at, you need an explicit typecast to void*, eg:

cout << static_cast<void*>(z)

That being said, the reason your code doesn't just fail outright is because the numeric value 15 (hex 0x0F) as an int happens to contain several 0x00 bytes in it (3 of them, if int is 4 bytes in size, as it is on most platforms). Depending on endian, the int will be laid out in memory as either 0F 00 00 00 or 00 00 00 0F. So, trying to print z as a null-terminated string will encounter one of those 0x00 bytes and interpret it as a null terminator. If the 0x0F byte is encountered first, it will simply be interpreted as an ASCII control character that has no visual representation. Either way, you won't see anything being printed to the console.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770