3 ms·
You still have a few bugs to fix (need to cast to uintptr_t after casting to void *, need to use printf with a proper format string) but now your code is valid.
by chongli 2y ago
You still have a few bugs to fix (need to cast to uintptr_t after casting to void *, need to use printf with a proper format string) but now your code is valid. I believe it's still implementation-defined because different implementations are free to lay out memory as they wish, say by including the use of padding bytes between values, or by changing the location of the stack and the direction it grows (up or down in memory). This means you cannot assume that the array q directly follows the array p in memory (they may be in the opposite order or they may be separated by padding bytes).
I created a working version of your code on Godbolt Compiler Explorer [1]. I tried it with a few different compilers and the code runs. The comparison evaluates to false on every compiler that I could get to work at all. Some don't seem to print anything at all, though the assembly they generate seems like it ought to.
As a general rule of thumb for C, you should assume it is impossible to reach the object pointed to by one pointer via another pointer, unless the second pointer directly aliases the first. You also cannot assume that the integer representation of a pointer corresponds directly to a valid address in memory. Virtual memory (with address translation), fat pointers, segmented memory, etc. are all possible which means the pointer's actual bit pattern should be considered an opaque structure handled by the implementation, not an integer for you to manipulate and then cast back to a pointer.
The main reason for wanting to convert a pointer into a uintptr_t type is to serialize it into some other structure in a one-way fashion, such as to store it in a hash table.
[1] https://godbolt.org/z/dT8G8o5xM https://godbolt.org/z/dT8G8o5xM
- James_K 2y agoThis code doesn't assume that q follows p, that's the trick to it. The way you are trying to explain this to me, I feel like you haven't read the article or understood the code snippet.
- chongli 2y agoAfter (re)reading the article I've come to the conclusion that with proper provenance tracking through the cast to an integer, the comparison: (iq == ip) Should be replaced (at compile time) with the constant 0 (or false, if you like). Since iq and ip have different provenances -- even though they may (or may not) be bitwise equal (which is entirely implementation-dependent in C) -- they can never be considered equal, so falsity can be deduced at compile time. It should also be considered invalid (and a compile-time error) to cast any old plain integer (one whose provenance is not a pointer) to a pointer, regardless of whether or not the address of said pointer lands on a live object, because an integer created by any means other than a cast from a pointer should have empty provenance. Edit: Ahhh, this provenance story is way messier than I thought. One serious problem with tracking provenance is that functions like memcpy become a huge headache to deal with.