2

If I am not mistaken, on a 64bit machine, a pointer is equivalent to a number between 0 and 2^64-1. Hence the following results:

printf("%p",    (void*)     -1); → 0xffffffffffffffff
printf("0x%lx", (uintptr_t) -1); → 0xffffffffffffffff

yet when I print a pointer from an object I just allocated, the results do not show the same width:

printf("%p", (void*) &myobject); → 0x70d940

Is there any reason why all my objects are (always) given an adress at the begining of the memory space ? Thanks to virtual memory the could be placed (from the program's point of view) basicaly anywhere in the 64bit space.

Also why doesn't %p print the full width by default ? (I would expect if to act like 0x%016lx)

Edit: Also, is there any reason why 0x018p is not valid ?

error : fanion « 0 » used with « %p » gnu_printf format
Amxx
  • 3,020
  • 2
  • 24
  • 45
  • 1
    `%p` can format the address in any way it chooses. It doesn't have to be hex (though it usually is); it doesn't have to start `0x` or `0X`; it might print hex in upper-case or lower-case. Try `printf("%p\n", (void *)0)` — on a Mac, that's just `0` even though other values are printed `0x1234` style. Try `printf("%p\n", (void *)1024);` — it probably prints a short address `0x400`. – Jonathan Leffler Jan 13 '17 at 16:20
  • Why do you think it is not _full width_? There's no way to control, anyway. That is a valid value. Think of the normal scenario, we write _"the loop goes from 1 to 100"_, we don't write, _"the loop goes from (001)10 to (100)10"_, right? – Sourav Ghosh Jan 13 '17 at 16:21
  • 1
    *I would expect if to act like `0x%016lx`* What is your expectation based upon? – Andrew Henle Jan 13 '17 at 16:22
  • @SouravGhosh: I don't know, that is my question. – Amxx Jan 13 '17 at 16:23
  • @AndrewHenle: It's based on my understanding of pointer and memory space. I'm not saying it's necessarily right, just if I am mistaken I would like an explaination – Amxx Jan 13 '17 at 16:25
  • How to display a number has nothing to do with your understanding of pointer and memory space. If you can't explain why you expected what you expected, then why did you expect it, and why is it a problem that your expectation isn't met? This is really weird. – Lightness Races in Orbit Jan 13 '17 at 16:26
  • Re "reason why all my objects are... at the beginning of the memory space": This is up to the Operating System. Usually the lower part of the virtual memory address space (excluding some *really* low addresses, to catch bad memory accesses) is reserved for loading the "user" parts of each process. Higher parts of the address space are reserved for the OS parts of the process (e.g. system libraries). – Danra Jan 13 '17 at 16:27
  • @LightnessRacesinOrbit I see `%p` as a way to specifically display pointer, which are not any number. The difference is the fixed width of pointers (for a given architecture) ... and I thought this fixed width should be reflected in the printing of those. – Amxx Jan 13 '17 at 16:29
  • `%p` prints the pointer address, period. There is nothing more to say. – Jabberwocky Jan 13 '17 at 16:31
  • _Is there any reason why all my objects are (always) given an adress at the begining of the memory space ? Thanks to virtual memory the could be placed (from the program's point of view) basicaly anywhere in the 64bit space_: yes they could be placed __anywhere__ in the 64bit space, including in a relatively low part. It's totally up to the OS. – Jabberwocky Jan 13 '17 at 16:33
  • 1
    @Amxx: I don't really know what else to tell you. Literally any number (of a native type) that you want to output is of a fixed width (for a given architecture), but we don't go around giving them all leading zeroes for no reason. It's extremely difficult to answer a question based on an false expectation, when you can't explain the expectation yourself! – Lightness Races in Orbit Jan 13 '17 at 16:42
  • "Is there any reason why all my objects are (always) given an adress at the begining of the memory space ?" Yes, the reason is: because it is available. Why would an implementation place the objects anywhere else? Beginning of the address space is a pretty natural place to start, isn't it? – AnT stands with Russia Jan 13 '17 at 16:48
  • What is this question intended to be about? Why does the output omit leading zeros? Or why are the objects placed at the beginning of the address space first? – AnT stands with Russia Jan 13 '17 at 16:50
  • The question is based on lack of reserach and lack of understanding what a pointer is and how `%p` works. The only thing are assumptions without explaining what they are based on. – too honest for this site Jan 13 '17 at 16:54

5 Answers5

5

As noted in a comment,

%p can format the address in any way it chooses. It doesn't have to be hex (though it usually is); the output doesn't have to start 0x or 0X; it might print hex in upper-case or lower-case.

Try printf("%p\n", (void *)0); — on a Mac, that prints just 0 even though other values are printed 0x1234 style. Try printf("%p\n", (void *)1024); — it probably prints a short address 0x400.

There are no requirements in the standards (POSIX or C or C++) specifying what the output from %p should look like.

If you want control over the format of pointers, use uintptr_t and the PRIzPTR macros from <inttypes.h>:

void *vp = 0;
printf("0x%.16" PRIXPTR " contains 0x%" PRIXPTR "\n",
       (uintptr_t)&vp, (uintptr_t)vp);

Or use PRIxPTR if you prefer lower-case hex digits. I don't, and I do like the 0x prefix, so that's what I use when I'm not constrained by someone else's questionable æsthetics.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
2

The exact representation of pointers via the %p format specifier is implementation defined.

From section 7.21.6.1 of the C standard:

p The argument shall be a pointer to void. The value of the pointer is converted to a sequence of printing characters, in an implementation-defined manner.

On Linux in particular, the man page states the following:

The void * pointer argument is printed in hexadecimal (as if by %#x or %#lx)

So if you are on Linux, you might be able to get away with using %#016lx

However, that's just one implementation, so you can't assume anything about the format in a conforming C application.

For example, on Turbo C running on DOS, a pointer actually contains two values, a segment and an offset.

dbush
  • 205,898
  • 23
  • 218
  • 273
2

Speaking mainly from a C perspective, since you've tagged [C] and you're using C-style code.

If I am not mistaken, on a 64bit machine, a pointer is equivalent to a number between 0 and 2^64-1.

Well that's a bit tricky. Pointers can be converted to integers and back, but the size required for an integer type to be capable of supporting all possible round-trip pointer-integer-pointer conversions without data loss is unspecified. Implementations are not required to provide such a type.

Moreover, pointers are not required to be represented as integer indexes into a flat address space, and indeed, historically, some implementations have used different representations. It is therefore not correct or safe to assert that a pointer is equivalent to a number, regardless of range.

Note also that this ...

printf("0x%lx", (uintptr_t) -1);

... is unsafe, inasmuch as it assumes that uintptr_t is unsigned long int, which is by no means guaranteed to be the case. The safe way to write a format string for a value of type uintptr_t is:

printf("0x%" PRIxPTR, (uintptr_t) -1);

(Uses inttypes.h)

Is there any reason why all my objects are (always) given an adress at the begining of the memory space ? Thanks to virtual memory the could be placed (from the program's point of view) basicaly anywhere in the 64bit space.

This is well beyond anything specified by C or C++, but yes, on a virtual-memory machine, your objects could be placed anywhere in the system's virtual address space. Why should they be, however? If your objects are dynamically allocated or have automatic duration then they are likely to be allocated in relatively consistent regions, because the system has regions that it uses for those purposes. If the objects have static duration then they might, in principle, be subject to ASLR, but that depends on the system, the C implementation, compilation options, and other details.

Also why doesn't %p print the full width by default ? (I would expect if to act like 0x%016lx)

Why should it do so? Your expectation is unjustified. printf() generally does not print leading zeroes unless you explicitly ask it to do so. C does not even require that the output be formatted as a hexadecimal number -- the format is completely implementation-defined.

Edit: Also, is there any reason why 0x018p is not valid ?

Because the standard explicitly says that the 0 flag character causes undefined behavior when used with the p conversion specifier. More generally, it produces UB when used with any conversion specifier other than d, i, o, u, x, X, a, A, e, E, f, F, g, or G. That's a long list of specifiers, but p is not on it. If you look carefully, you'll see that it's all the ones that specify conversion to numeric format, which, again, C does not specify p to do (though some implementations may so specify).

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1

It is because in most C++ implementations the pointer printing (%p) suppresses leading zeroes to make things more readable. You can use formatting tricks while printing to get the full address width.

EDIT: The 'formatting trick' I mentioned:

std::cout
<< "0x"
<< std::hex
<< std::noshowbase
<< std::setw(2)
<< std::setfill('0')
<< n
<< std::endl ;

Taken from https://stackoverflow.com/a/30326177/7407065

Community
  • 1
  • 1
16tons
  • 675
  • 5
  • 14
  • How is the _formatting trick_ applies here? Can you please elaborate? – Sourav Ghosh Jan 13 '17 at 16:35
  • This is rather a comment than an answer. You cannot comment? Well then you need to earn some reputation before. BTW: What is a _formatting_ trick? – Jabberwocky Jan 13 '17 at 16:36
  • @MichaelWalz It looks like it answers the question to me. Why don't you think this qualifies as an answer? – Jeremy Friesner Jan 13 '17 at 16:38
  • @JeremyFriesner it could be a reason but it isn't necessarily one. I didn't downvote though. – Jabberwocky Jan 13 '17 at 16:40
  • @JeremyFriesner Not trying to be rude, but in that regards, _"fix your code"_ can also be an answer, right? _what trick?_ is the essential part of the answer that's missing. :) – Sourav Ghosh Jan 13 '17 at 16:42
  • @SouravGhosh The question was: "Why doesn't %p show the full width of pointer?". The answer was: "It is because in most C++ implementations the pointer printing (%p) suppresses leading zeroes to make things more readable.". The question didn't ask for how to reformat the text, it only asked why the text was formatted the way it was. – Jeremy Friesner Jan 13 '17 at 16:49
  • @JeremyFriesner I don't disagree but don't you think this needs a little more elaboration for the _why_ part? First of all, it needed to mention that _most implementation ...._ part is valid because of the _implementation defined_ part mentioned in the standard. Secondly, if you're saying about a _proposed solution_, the solution, or at least, the approach should be mentioned, not just _a trick_ which can result in the _expected_ output. Just trying to improve the quality, not only for the OP but also for the future visitors. – Sourav Ghosh Jan 13 '17 at 16:58
  • @SouravGhosh I'm in favor of improving quality as well; but a bare-bones answer is still an answer, and not a comment. – Jeremy Friesner Jan 17 '17 at 04:43
0

Also why doesn't %p print the full width by default?

Printing the full width of pointers by default breaks the style of printf(). A "full width" option is available through modifiers.

The various unmodified specifiers print minimal text.

printf("%d", INT_MIN);
// "-2147483648"   example
printf("%d", 123);
// "123", not "+0000000123"

double value_nearest_one_seventh = 1/7.0;
printf("%f", value_nearest_one_seventh);
// "0.142857" 
// instead of its exact value of
// 0.142857142857142849212692681248881854116916656494140625

Should code need to print a pointer to a fixed width, use the length modifier.

void *ptr = ptr;
int pointer_print_width = sizeof("0xffffffffffffffff") - 1;
printf("<%*p>", pointer_print_width, ptr);
// <          0x28cc6c>
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256