addresses and integers

D

Dan Pop

Of course, for some implementations it's hard to see how %p plus
hypothetical flags or precision modifiers would produce a well-
defined format. On the AS/400, for example, %p produces a relatively
verbose description of the address, including object space name and
offset.

Which doesn't mean that it wouldn't be useful for the vast majority of
implementations. Not very useful, because few applications need %p at
all, but quite useful for the few that do (most likely, for debugging
purposes).
But there's always the array-of-unsigned-char representation, which
*is* well-defined anywhere; the only variable is its length.

The array-of-unsigned-char representation is not particularly meaningful,
as its interpretation is affected by byte order issues (and,
theoretically, by padding bits issues).

Dan
 
W

Wojtek Lerch

Dan said:
Code that depends on an optional feature of the language cannot reliably
achieve its goal, period. And the existence of uintmax_t doesn't prove
that the result of the conversion is suitable for *any* purpose other
than replacing pointer comparison for equality by integer comparison
for equality; [...]

Where does the standard promise that if two pointers compare equal, then
converting them to uintptr_t will produce the same value?
 
D

Dan Pop

In said:
Dunno for certain, but can't we thank Microsoft for that? I don't think the
segment / offset was part of the Intel hardware, but an OS thing.

That's either patent ignorance or patent stupidity. The segment/offset
model for memory addressing has *always* been part of the Intel 80x86
architecture.
I don't
recall having to go to new hardware when MS decided the flat memory model
was better...

I do: the flat memory model made sense only when the Intel processors
started to support 4 GB segments, so that the whole system could use a
single segment. Before the 386, a flat memory model would have meant
a system restricted to a 64 kB address space. And MSDOS compilers
did offer such a model, the "tiny" memory model. The fans of von Neumann
architectures could also use the "small" memory model, with a 64 kB
data address space and 64 kB code address space. Both models were
purely liniar, with 16-bit data and function pointers.

Dan
 
D

Dan Pop

In said:
Dan said:
Code that depends on an optional feature of the language cannot reliably
achieve its goal, period. And the existence of uintptr_t doesn't prove
that the result of the conversion is suitable for *any* purpose other
than replacing pointer comparison for equality by integer comparison
for equality; [...]

Where does the standard promise that if two pointers compare equal, then
converting them to uintptr_t will produce the same value?

The result of the conversion from pointer to integer being implementation
defined, it's not clear if the implementation is free to throw in some
random bits in the result of the conversion, that are ignored when the
integer is converted back to pointer.

Dan
 
D

David Hopwood

Dan said:
Wojtek Lerch said:
Dan said:
Code that depends on an optional feature of the language cannot reliably
achieve its goal, period. And the existence of uintptr_t doesn't prove
that the result of the conversion is suitable for *any* purpose other
than replacing pointer comparison for equality by integer comparison
for equality; [...]

Where does the standard promise that if two pointers compare equal, then
converting them to uintptr_t will produce the same value?

The result of the conversion from pointer to integer being implementation
defined, it's not clear if the implementation is free to throw in some
random bits in the result of the conversion, that are ignored when the
integer is converted back to pointer.

I would have thought it was clear that it *is* free to do this (or to
convert pointers to uintptr_t values that are not unique for other reasons,
for instance because they include segment selectors). uintptr_t is in
general not useful except in non-portable code that "knows" what the
implementation-defined mapping is.

David Hopwood <[email protected]>
 
N

Niklas Matthies

In said:
Dan said:
Code that depends on an optional feature of the language cannot reliably
achieve its goal, period. And the existence of uintptr_t doesn't prove
that the result of the conversion is suitable for *any* purpose other
than replacing pointer comparison for equality by integer comparison
for equality; [...]

Where does the standard promise that if two pointers compare equal, then
converting them to uintptr_t will produce the same value?

The result of the conversion from pointer to integer being implementation
defined, it's not clear if the implementation is free to throw in some
random bits in the result of the conversion, that are ignored when the
integer is converted back to pointer.

The implementation may not need to throw in "random bits" in the
result or ignore them on converting back for this to happen. Pointers
that compare equal are not required to have the same representation.
If the conversion is based on pointer representation rather than on
abstract pointer value (as defined by equality comparison), then what
Wojtek Lerch describes happens naturally.

With x86 16-bit segment:eek:ffset pointers, for example, 000A:7B60 and
000B:7B50 will compare equal, and may well convert to 0x000A7B60 and
0x000B7B50, respectively.

-- Niklas Matthies
 
E

Eric Sosman

Dan said:
That's either patent ignorance or patent stupidity. The segment/offset
model for memory addressing has *always* been part of the Intel 80x86
architecture.




I do: the flat memory model made sense only when the Intel processors
started to support 4 GB segments, so that the whole system could use a
single segment. Before the 386, a flat memory model would have meant
a system restricted to a 64 kB address space. And MSDOS compilers
did offer such a model, the "tiny" memory model. The fans of von Neumann
architectures could also use the "small" memory model, with a 64 kB
data address space and 64 kB code address space. Both models were
purely liniar, with 16-bit data and function pointers.

Dan's explanation of the "small" model also illustrates
a reason why data pointers and function pointers aren't
interconvertible or comparable.

uintptr_t dp = (uintptr_t) stdout; // data pointer
uintptr_t fp = (uintptr_t) printf; // function pointer

It is conceivable that `dp' and `fp' could be equal, but
quite obviously the original pointers `stdout' and `printf'
point to completely different things. "The" address 0x1234
might actually be two different locations with completely
different contents, depending on whether it's interpreted
as a data address or as a code address.
 
J

James Kuyper

Dan Pop wrote:
....
... And the existence of uintmax_t doesn't prove
that the result of the conversion is suitable for *any* purpose other
than replacing pointer comparison for equality by integer comparison
for equality;

Citation, please - where does the standard say anything that connects
those two equality comparisons?

An entirely plausible situation, and one I've actually seen, is that two
pointers with different bit patterns can represent the same physical
location, and therefore compare equal, but they get converted to
integers that correspond to the bit patterns, and therefore compare unequal.

On the other hand, if the integers do compare equal, then it seems to me
that they must have been converted from pointers that compared equal.
... the standard doesn't guarantee any other property for the
result of the conversion to uintptr_t. ...

The only property the standard does guarantee is that the result, if
converted back to the original pointer type, compares equal to the
original pointer.
 
K

Kenneth Brody

Niklas Matthies wrote:
[...]
With x86 16-bit segment:eek:ffset pointers, for example, 000A:7B60 and
000B:7B50 will compare equal, and may well convert to 0x000A7B60 and
0x000B7B50, respectively.

Are you sure that those two pointers will compare equal? Yes, in real
mode, they point to the same physical address. But, who says that the
pointers need to be "normalized" before being compared?

It's been a while since I've done 16-bit real mode x86 programming, but
the last time I did, I'm pretty sure that the compiler (which probably
wouldn't qualifiy as "ANSI compilant" today) would not have compared the
above pointers as "equal" unless you were in huge model.

Does the standard say that two pointers must compare as "equal" if and
only if they point to the same memory location, regardless of the bit-
level representation of the pointers?
 
K

Keith Thompson

Eric Sosman said:
Dan's explanation of the "small" model also illustrates
a reason why data pointers and function pointers aren't
interconvertible or comparable.

uintptr_t dp = (uintptr_t) stdout; // data pointer
uintptr_t fp = (uintptr_t) printf; // function pointer

It is conceivable that `dp' and `fp' could be equal, but
quite obviously the original pointers `stdout' and `printf'
point to completely different things. "The" address 0x1234
might actually be two different locations with completely
different contents, depending on whether it's interpreted
as a data address or as a code address.

Right, and that can happen (at least theoretically) even if the
hardware doesn't have separate address spaces for instructions and
data. A function pointer could plausibly be implemented as an index
into a table rather than as a machine address. (The AS/400 probably
does something at least that weird.)
 
J

James Kuyper

Kenneth Brody wrote:
....
Does the standard say that two pointers must compare as "equal" if and
only if they point to the same memory location, regardless of the bit-
level representation of the pointers?

Yes.
 
J

Joe Wright

Dan said:
Dan said:
Code that depends on an optional feature of the language cannot reliably
achieve its goal, period. And the existence of uintptr_t doesn't prove
that the result of the conversion is suitable for *any* purpose other
than replacing pointer comparison for equality by integer comparison
for equality; [...]

Where does the standard promise that if two pointers compare equal, then
converting them to uintptr_t will produce the same value?


The result of the conversion from pointer to integer being implementation
defined, it's not clear if the implementation is free to throw in some
random bits in the result of the conversion, that are ignored when the
integer is converted back to pointer.

As we get older, I'm told that memory is the second thing to go.
I've forgotten what the first thing was.

But I've forgotten why it might have been useful to store a pointer
value in an integer object, and then use the integer as a pointer
value. As far as I remember, I have never attempted it but, as we
get older..
 
B

Brian Inglis

Kenneth Brody wrote:
...

Yes.

But, and this is not the same thing, does the standard now say that
two pointer values that point to the same memory location must compare
equal?
I'm thinking here of x86 segmented addresses, where if you (say)
incremented a pointer to arrays of 16 chars, and serially incremented
a pointer to char by 16, to get to the same place, the compiler might
increment the segment in the former case, the offset in the latter
case, resulting in two different representations of the same address.
 
B

Brian Inglis

The standard says that it's valid (with one exception) and that the
result is implementation-defined.


It may be possible (AS/400 springs to mind) that no integer type is
wide enough to hold the result of the conversion. This is the exception
mentioned above.

As for the implementation-defined result, there are architectures, like
the 8086, where the pointer value is not the same as the address pointed
to and most addresses can have 4096 different representations as pointer
values.


In some cases, see above, it may be more than one integer value. The
actual address is computed by the CPU itself, from these numbers.


You can do that, but the result need not have the desired/expected
meaning. You have to understand how the conversion works on a given
platform (the implementation must document it) in order to do this kind
of things in a meaningful way. Which means that the code cannot be
expect to work as intended on another implementation.

There need not be any meaningful computed result possible with an
integer representation of an address, as in 286 protected mode, where
the segment number is just a selector number. The selector number is
used to look up the segment real base address, size, and other
properties in a segment table inaccessible to user programs. After its
first lookup, those segment attributes are loaded into inaccessible
internal CPU registers, to avoid future lookups of the same values.
 
W

Wojtek Lerch

James Kuyper said:
Kenneth Brody wrote:
...

Yes.

It's acceptable for a pointer to one past the end of an array to trap when
dereferenced, but to compare equal to a pointer to some other object. I
guess you could argue that those pointers point to the same "memory
location", but it feels like a bit of a stretch to me...
 
W

Wojtek Lerch

Brian Inglis said:
But, and this is not the same thing, does the standard now say that
two pointer values that point to the same memory location must compare
equal?

6.5.9p6 "Two pointers compare equal if and only if [...] both are pointers
to the same object [...]"
 
M

Mabden

Brian Inglis said:
But, and this is not the same thing, does the standard now say that
two pointer values that point to the same memory location must compare
equal?
I'm thinking here of x86 segmented addresses, where if you (say)
incremented a pointer to arrays of 16 chars, and serially incremented
a pointer to char by 16, to get to the same place, the compiler might
increment the segment in the former case, the offset in the latter
case, resulting in two different representations of the same address.

I am no standards guru - I don't a copy. But I have an opinion anyway.

As far as I understand, any two pointers that point to the same object are
equal, when the compiler knows they point to the same object.

If you want to play magic semantic games with the compiler to fool it, it
may consider them not equal.

How is this beneficial to programming actual software? Do you have a real
world pointer problem you wish to discuss?
 
D

Douglas A. Gwyn

David said:
... uintptr_t is in
general not useful except in non-portable code that "knows" what the
implementation-defined mapping is.

It's really meant to retrofit yucky existing code
that relied on punning pointer values with integers,
to provide a larger measure of portability than they
originally had. We strongly discourage using
intptr_t in newly created code. It is perhaps
possible to think of a legitimate use for which no
suitable alternative exists, but I don't know of one.
 
D

Douglas A. Gwyn

Kenneth said:
Does the standard say that two pointers must compare as "equal" if and
only if they point to the same memory location, regardless of the bit-
level representation of the pointers?

Essentially, yes (6.5.9p6). Note, however, that valid
pointer values can be formed only in certain ways, so
for example int i, j, *pi = &i, *pj = &j - 1; pi == pj;
is not allowed in a s.c. program. The opportunity for
accidental equality is thus pretty much limited to
int i, j, *pi = &i + 1, *pj = &j; pi == pj;
Other, more useful, cases of equality will be for two
pointers into (or just past the end of) an aggregate
object.
 
C

Charles Sanders

I agree. However, a large percentage of current
machines all effectively use the same implementation defined
mapping, but you cannot rely on it.
[snip
.... It is perhaps
possible to think of a legitimate use for which no
suitable alternative exists, but I don't know of one.

One possibility is (hardware and operating system
dependant) speeding up a bottleneck. It could be possible
that converting to integer and checking pointer alignment
may permit the selection at run time (or even compile time
if the pointer alignment is known to the compiler) of a
particularly efficient implementation (on this particular
hardware) of a routine provided the alignment restrictions
are met. A slower, more general routine would be used in
other cases. On vector hardware, this can be a very big win.

Charles
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,146
Messages
2,570,832
Members
47,374
Latest member
anuragag27

Latest Threads

Top