-1

I can compile and execute this line with no issue:

int whoami = i->whoami;
uint8_t * fetchPTR = &in[dataSize];
printf("%d, init fetch ptr = %08X\n",whoami, fetchPTR);

However, using fprintf I am receiving this warning:

warning: format specifies type 'unsigned int' but the argument has type 'uint8_t *' (aka 'unsigned char *') [-Wformat]

and it suggests me to use %s instead.

Can anyone explain this behavior?

Amir
  • 1,348
  • 3
  • 21
  • 44

1 Answers1

4

%X is strictly the size of an unsigned int, so on any machine where sizeof unsigned int != sizeof uint8_t* (e.g. most 64 bit machines), it wouldn't print the whole value of the pointer. The %p format code will print pointers with pointer-size properly accounted for, so use that to print memory addresses.

To be clear, as noted in the comments below, this is actually undefined behavior even when sizeof unsigned int == sizeof uint8_t*; pointers are stored in integer-like ways on all modern hardware I'm aware of, but some future system could break that equivalence, and adhering to the language standard is the only way to guarantee portability. Similarly, to be fully compliant, you should cast your pointer to void* to print as %p specifically works with void*, not "pointers in general"; on weird systems (e.g. segmented memory systems with a concept of near and far pointers, or separate memory spaces for different pointer types), uint8_t* and void* might not be equivalent in how they are stored or represented, but casting to void* should always work.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • 2
    It's not just a truncation issue - mismstching type specifiers and actual types is undefined behavior. Sure, today the calling convention on common systems is the same for pointers and integers, but so it was for `float` and `int` on 32 bit x86 - until on x86_64 it wasn't anymore, and mismstching fp with int arguments became a huge headache. – Matteo Italia Jan 08 '19 at 01:07
  • 3
    However, `%p` specifically prints pointers of type `void *`. The representation of `void *` does not necessarily have to be the same as the representation of any other pointer type, so for strict conformance it is necessary to cast the corresponding argument to type `void *`. – John Bollinger Jan 08 '19 at 01:09
  • 2
    Also, when passing pointers to display with `%p` the corresponding value must be casted to `void *` if it already isn't such. Again, on mainstream machines it's irrelevant, but who knows about tomorrow (or esoteric hardware, with different pointer sizes depending from type?). **edit** welp 13 seconds late – Matteo Italia Jan 08 '19 at 01:09
  • I am tempted to vote this down because, even with the edit, the answer improperly suggests that the issues about printing the wrong thing are largely about width and representation. They are not. Certainly the C standard grew out of issues dealing with varying widths and representations across different computing platforms, but it has grown into abstractions. You **must** obey the rules in the C standard—properly matching types of arguments to the types required by format specifiers—or the behavior is not defined by the standard and may fall victim to aggressive compiler optimizations. – Eric Postpischil Jan 08 '19 at 02:12
  • As an example, we can imagine a platform where pointers are indeed simple integers—but they are also checked with checksums to guard against malicious exploits. Some processors already have features like this, and passing a pointer to a function might require something more than passing a simple integer, even if they are nominally the same size. We should be guiding people toward coding in conformance with the standard, using knowledge about internals such as representations as useful for understanding but not to be used as an excuse for kludging non-portable code. – Eric Postpischil Jan 08 '19 at 02:15