addresses and integers

D

Dan Pop

In said:
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

Not to store a pointer value in an integer object but to convert a
pointer value to an integer value. Big difference!
value. As far as I remember, I have never attempted it but, as we
get older..

You receive a pointer value from the caller and you need to check whether
it's properly aligned for its intended purpose or not.

Try to write a highly optimised memcpy-like function in (as portable as
reasonably possible) C and see how far you can get without converting
both pointers to integers.

Dan
 
F

Flash Gordon

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.

Another common reason for using the integer to pointer conversion (but
not pointer to integer conversion) is for accessing memory mapped
hardware on an embedded system. I've done this myself where the compiler
vendor documented this as being the preferred method of handling the
problem.
 
J

James Kuyper

James said:
Kenneth Brody wrote:
...



Yes.

Before anyone jumps on that answer, let me point out that while it's
basically true, there are some fuzzy issues. The fundamental problem is
that there are at least two kinds of pointers that a strictly conforming
program can legally use, but cannot legally dereference. Therefore,
it's not meaningfully guaranteed that they point at any location, and a
conforming implementation of C could implement them in a way that
renders the question "where does that pointer point?" meaningless. The
standard handles these as special cases.

The first kind is null pointers. All null pointers compare equal to each
other, and unequal to any pointer to an object.

The second kind of such pointers are the ones that are one element past
the end of an array. For this purpose, non-array objects count as
one-element arrays. A pointer one past the end of array compares equal
to any other pointer one past the end of the same array, and unequal to
any pointer to any other element of the same array. The standard permits
a pointer one past the end of one array to compare equal to a pointer to
the beginning of another array; this allows the obvious implementation
of pointers on most platforms, without requiring that there be unused
padding at the end of each object.

If you think of all null pointers as pointing at the same unusable
location, and all pointers one past the end of an a array as pointing at
a location which is where the next element of the array would go, if it
were one element larger, then all these special case rules become
obvious; they're just examples of the general rule that pointers compare
equal if and only if they point at the same memory location. However,
since you can't legally de-reference these pointers, the standard does
not require that the "thinking" I described in the first sentence of
this paragraph is true. That's why the standard handles them as special
cases.

Real world example: I remember one implementation of C for a
segment-offset architecture, where all pointers with an offset of 0 were
treated as null pointers, regardless of the segment value. It was very
meaningful on that platform to talk about where the null pointer
pointed: if the address it contained were passed to assembly language
code, it would access a very specific byte in memory, and it would be a
different byte for different null pointers. However, all null pointers
compared equal to each other, as required by the C standard, despite the
fact that they pointed at different locations. This wasn't a fully
conforming implementation of C, but the way it handled null pointers
wasn't one of it's areas of non-conformance.
 
J

James Kuyper

Brian 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?

Yes - that's what the "only if" part of 6.5.9p6 means.
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.

And those representations must compare equal. It's up to the compiler to
perform the comparison of pointers in such a way that this is true.
 
D

Dan Pop

In 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
^^^^^^^^^^^^^^^^^^^
That's undefined behaviour, just like any other attempt to convert a
function pointer to an integer. Even the first conversion must be
written as (uintptr_t)(void *)stdout, because uintptr_t is guaranteed to
work only for void pointers.

Dan
 
L

lawrence.jones

In comp.std.c James Kuyper said:
Kenneth Brody wrote:
...

Yes.

Provided no undefined behavior has occurred. So, if there are multiple
possible representations for the same memory location (like in the 8086
segmented address model) but valid operations always generate the same
representation, the compiler need not canonicalize the representations
before comparing them.

-Larry Jones

Honey, are we out of aspirin again? -- Calvin's Dad
 
J

James Antill

You receive a pointer value from the caller and you need to check whether
it's properly aligned for its intended purpose or not.

Try to write a highly optimised memcpy-like function in (as portable as
reasonably possible) C and see how far you can get without converting
both pointers to integers.

I've seen people change the pointers to _pointers to integers_, to do
"large" copies per iteration, but not convert them to integers themselves.
 
P

pete

Chris said:
The only portable and safe way to do pointer arithmatic is with
subscripts. e.g.
int * ptr;
ptr = &ptr[1]; /* next integer */

Will work whatever the size of your integer, and,
whatever the size of your address.

As does `ptr += 1`.

I usually spell that as '++ptr'.
 
G

Guest

According to Douglas A. Gwyn said:
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.


Pointer hashing is an extremely useful technique that is most
easily done by converting the pointer to an integer type first.
In theory, one could hash the unsigned char bytes constituting
the pointer whether or not intptr_t exists, but the integer
hash is likely to be faster, and pointer hashing is often done
for performance. Also, I suspect that implementations with
multiple pointer representations are likely (although not guaranteed)
to normalize their pointers before conversion to intptr_t,
precisely to support that "yucky existing code," which would make the
integer conversion more robust (although not 100% portable).

Pointer hashing isn't quite 100% portable, but it's useful on
a wide variety of platforms of practical interest, and all
the 100% portable alternatives I know of have significant additional
costs in time, memory, or program flexibility.
 
C

Charles Sanders

James said:
I've seen people change the pointers to _pointers to integers_,
to do "large" copies per iteration, but not convert them to
integers themselves.

But to use pointers to int you usually need to check alignment,
and this typically needs conversion to int, eg on most common
32 bit hardware

if( ((unsigned int)p1)&0x03 || ((unsigned int)p2)&0x03 )
{ /* Not aligned on 4-byte boundary, byte by byte copy */ }
else
{ /* Aligned on 4 byte boundary, 4 byte word by word copy */ }

or on a Cray Y-MP (8 byte words, byte offset in high order bits)

if( ((unsigned int)p1)&0xe000000000000000
|| ((unsigned int)p2)&0xe000000000000000 )
.....

Of course, checks on the count should also be used to make
sure the extra set up is worth it and to handle counts that are
not a multiple of the word size correctly. If the pointers are
unaligned but differ by a multiple of the "word" size copy
operations may be split over multiple loops, with the bulk of
the work done in a loop over words. Also, checks for 2-byte (use
shorts to copy) or 8 byte (use 64 bit ints) alignment can also
be done to select the most efficient method possible.

Charles
 
J

junky_fellow

Not to store a pointer value in an integer object but to convert a
pointer value to an integer value. Big difference!


You receive a pointer value from the caller and you need to check whether
it's properly aligned for its intended purpose or not.

Try to write a highly optimised memcpy-like function in (as portable as
reasonably possible) C and see how far you can get without converting
both pointers to integers.

Dan

can we test portably whether a pointer is word-aligned or not?
i have seen some programs that typecast pointer to int and then do
some arithmetic operation. Is that mean that those programs are non
portable ?

thanx in advance for any help...
 
D

Dik T. Winter

> can we test portably whether a pointer is word-aligned or not?
No.

> i have seen some programs that typecast pointer to int and then do
> some arithmetic operation. Is that mean that those programs are non
> portable ?

Yes.
 
M

Michael Wojcik

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).

Sure. I wouldn't object to a definition in the standard for width
and precision specifications for %p, with a caveat that says they
could be ignored by the implementation if deemed not meaningful
(though actually I suppose they would be meaningful even on the '400,
if precision were interpreted as it is for %s). Then it becomes a
QoI issue.
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).

I'm not sure about that; in cases where %p is useful, whatever is
processing the output generally has to know how to interpret it, and
the same would be true of the array-of-unsigned-char output. Its
meaning will be implementation-dependent in either case. And in
either case it should be valid to read it back in during the same run
and reconstruct the pointer from it. The main advantage of %p seems
to be that it doesn't require multiple *printf calls in a loop to be
portable (unlike the array-of-unsigned-char version, which does, since
the length differs among implementations).
 
C

CBFalconer

junky_fellow said:
.... snip ...

can we test portably whether a pointer is word-aligned or not?

No. By storing the address of an object of <type> in a pointer we
ensure it is properly aligned for <type>. Pointers returned by
malloc are guaranteed aligned for any type. Structures and unions
are already aligned for any contained type. So there is
absolutely no need for any such test. If you apparently have such
a need your code is mis-organized.
i have seen some programs that typecast pointer to int and then do
some arithmetic operation. Is that mean that those programs are non
portable ?

Yes. Actual alignment requirements are system dependant.
 
D

Dan Pop

In said:
can we test portably whether a pointer is word-aligned or not?

No. This is why I wrote "as portable as reasonably possible" above.
i have seen some programs that typecast pointer to int and then do
some arithmetic operation. Is that mean that those programs are non
portable ?

They are not maximally portable, but they work on the pointer model used
by practically all byte-addressed systems with a linear address space,
only "fat" pointers could break them, but "fat" pointers are not exactly
the kind of feature the average programmer will ever see during his
entire career.

Dan
 
D

Dan Pop

In said:
I've seen people change the pointers to _pointers to integers_, to do
"large" copies per iteration, but not convert them to integers themselves.

How do you check that the pointer is aligned for an integer access?
If it isn't, how do you align it?

Dan
 
D

Dan Pop

I'm not sure about that; in cases where %p is useful, whatever is
processing the output generally has to know how to interpret it, and
the same would be true of the array-of-unsigned-char output.

In most cases, that would be a human reading a hex number. If the hex
number is generated by %p, it is supposed to be the actual address
(although, strictly speaking, this is a QoI issue), if the hex number
is a mere concatenation of the bytes composing the array, the human
would have to do the interpretation himself, taking into account all the
issues mentioned in my previous post.

Dan
 
D

David R Tribble

No. By storing the address of an object of <type> in a pointer we
ensure it is properly aligned for <type>. Pointers returned by
malloc are guaranteed aligned for any type. Structures and unions
are already aligned for any contained type. So there is
absolutely no need for any such test. If you apparently have such
a need your code is mis-organized.

Except, of course, when you are trying to do system-dependent things, such
as really fast memory-copy functions, in which case you will have some
knowledge about the characteristics of pointers, addresses, and words of
the underlying CPU and memory. You might also want to write your own
memory allocation functions that return smaller blocks of memory that are
not necessary aligned for every possible datatype. Or maybe you're writing
device drivers that access I/O ports or specially mapped memory addresses.
Or perhaps you're writing a process debugger for a particular CPU and it
validates memory accesses as they are attempted. And so forth. There are
all sorts of valid applications that need to treat pointers as integer
values.


For example, a memcpy() function for an Intel iAPX/386 architecture can
take advantage of the fact that moving 4-byte words is much faster than
moving single bytes at a time. The Intel architecture allows fullword
accesses that are not full-word aligned (i.e., whose addresses are not
even multiples of 4), but exacts some additional clock cycles for doing so.
So converting pointers to integers is useful for detecting and making
adjustments for unaligned memory accesses.

The Motorola 68000 architecture, in contrast, allows only word-aligned
word accesses (i.e., a pointer must have a low bit of 0). So converting
pointers to integers is useful for detecting unaligned access attempts
before they occur.


None of this code is very portable, of course, but most programs are
not written to be universally portable in the first place.

-drt
 

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