arithmetic operations on pointer

K

Kenny McCormack

Barry Schwarz said:
You cannot perform arithmetic on a pointer to void. ....
Note that void is an incomplete type. There is no concept of a void
to the left of the current void. And sizeof(void) is invalid.

This is, of course, true in the standards jockey sense.

But gcc treats "void *" as being the same thing as "char *" which, for all
practical purposes, it is.
 
T

Tim Rentsch

Eric Sosman said:
[On the quesiton of how to allocate memory having a specified
alignment], I do not believe there is a fully-portable solution.
Every C implementation has some way to solve the problem,

If you mean every existing implementation, that may be true. If
you mean every possible conforming implementation, it is not true,
as the question may not even make sense in some environments.

but no
single solution is guaranteed to work for all C implementations.

Certainly not for every conceivable conforming implementation,
but there may be a solution in the practical sense that it works
for all existing implementations and is likely to work on all
reasonably plausible future implementations.
 
T

Tim Rentsch

I don't think uintptr_t is needed.

It is needed given the context in which the comment was made.
That context was present in my posting, so you must have snipped
it.
You are assuming that the alignment of a pointer p can be deduced
from the lowest bits of (uintptr_t) p.

I'm not assuming any such thing. My comments are about how to
carry out a certain computation, the original expression for
which came from a page on stackoverflow.com; they are concerned
only with what types are needed to carry out the computation in
a meaningful way, and did not depend on any assumptions about
where the low bits of a pointer might end up. How the result is
used might depend on such an assumption, but the comments above
aren't about that.
I would assume that it can just as well be deduced from the
lowest bits of (unsigned char) p, for example (for alignment up
to 256 bytes).

That assumption is dangerous, and I don't reason to take on
take on the additional risk. The Standard makes some
guarantees about converting pointer values to (uintptr_t);
it makes no guarantees about converting pointer values to
(unsigned char), which very likely is undefined behavior on
any implementation where CHAR_BIT == 8. More practically,
there's a good chance a compiler will complain if it sees
a pointer value being converted to (unsigned char); for
example, gcc issues a warning for it even without a -Wall or
a -Wextra (or any -W's) being given.
 
T

Tim Rentsch

Keith Thompson said:
That requires an additional assumption: that converting a pointer to
a narrow integer type copies the "low-order" bits of the pointer.
It's likely to be correct, but why make extra assumptions when you
don't really have to?

Especially since converting a pointer to a character type is
likely to be undefined behavior, and not just some unexpected
implementation-defined behavior.
On the other hand, using uintptr_t assumes that uintptr_t actually
exists.

Note that I did say "or the moral equivalent ..." about uintptr_t.
The original context (present in my posting but later snipped)
tacitly assumed the existence of some type like uintptr_t; it
seems reasonable to reference that conceptual type as "uintptr_t",
since what is being discussed is only what makes sense given the
context of the original (and now snipped) expression, not any
absolute statement about whether that approach is a good idea.
 
T

Tim Rentsch

anish kumar said:
but ptr is a pointer to void so if i subtract -1 from it
and then cast it to void ** and do a derefrence as below
then how it is different:
*((void **)(ptr -1))

Here is another way to think of it. Suppose the type of p is
'int *' and we are doing a conversion to 'char *'. Consider the
two expressions

((char *) p) + 1 and (char *) (p+1)

The expression on the left points one byte beyond where p points,
because sizeof (char) == 1. The expression on the right points
four bytes beyond where p points (assuming sizeof (int) == 4).
These results hold because of how pointer arithmetic is defined -
adding 1 to a pointer steps over exactly the number of bytes
needed for the type that the pointer expression points to. This
type is 'char' for the left hand expression, because of the cast,
and 'int' for the right hand expression, because of what we said
about p to start with.

Now take the case when the type of p is 'void *' and we are
converting to 'void **' :

((void **) p) + 1 and (void **) (p+1)

The expression on the left points (sizeof (void *)) bytes beyond
where p points. The expression on the right points (sizeof (void))
bytes beyond where p points. If sizeof (void *) == sizeof (void)
then these results would be the same. Do you think that these two
sizes, sizeof (void *) and sizeof (void), have the same value?
What values do you think they have?
 
T

Tim Rentsch

This is, of course, true in the standards jockey sense.

Right, but more importantly it is correct due to other practical
considerations.
But gcc treats "void *" as being the same thing as "char *"
which, for all practical purposes, it is.

The second half of this statement is clearly incorrect. There are
plenty of compilers other than gcc that do not allow arithmetic on
(void *) pointers, and groups who use these compilers often do so
for practical reasons.
 
K

Keith Thompson

Tim Rentsch said:
Especially since converting a pointer to a character type is
likely to be undefined behavior, and not just some unexpected
implementation-defined behavior.

Good point. N1570 6.3.2.3p6:

Any pointer type may be converted to an integer type. Except as
previously specified, the result is implementation-defined. If the
result cannot be represented in the integer type, the behavior is
undefined. The result need not be in the range of values of any
integer type.

Given CHAR_BIT == 8, it seems that there are at most 256 distinct
pointer values that can be converted to unsigned char without
triggering undefined behavior -- and it's likely that most of those
256 values are not valid pointer values anyway.

Still, it would be unsurprising for such a conversion to yield the
low-order 8 bits of the pointer value under typical implementations.
Note that I did say "or the moral equivalent ..." about uintptr_t.
The original context (present in my posting but later snipped)
tacitly assumed the existence of some type like uintptr_t; it
seems reasonable to reference that conceptual type as "uintptr_t",
since what is being discussed is only what makes sense given the
context of the original (and now snipped) expression, not any
absolute statement about whether that approach is a good idea.

If uintptr_t doesn't exist (in an implementation that conforms
to C99 or C11), it's almost certainly because no unsigned integer
type exists that meets the requirement that conversion from void*
and back again yields the original pointer value. In that case,
I'm not sure what the "moral equivalent" could be. (The standard
merely says that uintptr_t is optional, and doesn't explicitly
state that it's ever required, but IMHO failing to provide it when
possible would be silly.)
 
T

Tim Rentsch

Keith Thompson said:
If uintptr_t doesn't exist (in an implementation that conforms
to C99 or C11), it's almost certainly because no unsigned integer
type exists that meets the requirement that conversion from void*
and back again yields the original pointer value. In that case,
I'm not sure what the "moral equivalent" could be.

Like I was trying to say before, the original context presupposes
an integer type capable of holding all the bits of a pointer. My
remarks were made within that context, ie, taking as given that
there is an integer type wide enough to hold a pointer. So the
moral equivalent of uintptr_t is that type, whether uintptr_t
is defined or not. My comments were meant to be taken relative
to the earlier suggestion, and interpreted in that light, not
as an independent statement.
 
K

Keith Thompson

Tim Rentsch said:
Like I was trying to say before, the original context presupposes
an integer type capable of holding all the bits of a pointer. My
remarks were made within that context, ie, taking as given that
there is an integer type wide enough to hold a pointer. So the
moral equivalent of uintptr_t is that type, whether uintptr_t
is defined or not. My comments were meant to be taken relative
to the earlier suggestion, and interpreted in that light, not
as an independent statement.

What you wrote upthread was:

The only plausible choice for the pointer operand is uintptr_t
(or the moral equivalent in C90, etc), which will be wide enough
to represent the result so the right hand side cast could be
to that type.

The "in C90, etc" makes all the difference. In C99 and later, if
there is an unsigned integer type wide enough to hold a pointer,
then uintptr_t will exist (unless the implementation is perverse
enough that it omits uintptr_t unnecessarily). I didn't realize
until I searched upthread just now that pre-C99 implementations
were under discussion.
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
Keith Thompson said:
[...]
On the other hand, using uintptr_t assumes that uintptr_t actually
exists.

Note that I did say "or the moral equivalent ..." about uintptr_t.
The original context (present in my posting but later snipped)
tacitly assumed the existence of some type like uintptr_t; it
seems reasonable to reference that conceptual type as "uintptr_t",
since what is being discussed is only what makes sense given the
context of the original (and now snipped) expression, not any
absolute statement about whether that approach is a good idea.

If uintptr_t doesn't exist (in an implementation that conforms
to C99 or C11), it's almost certainly because no unsigned integer
type exists that meets the requirement that conversion from void*
and back again yields the original pointer value. In that case,
I'm not sure what the "moral equivalent" could be.

Like I was trying to say before, the original context presupposes
an integer type capable of holding all the bits of a pointer. My
remarks were made within that context, ie, taking as given that
there is an integer type wide enough to hold a pointer. So the
moral equivalent of uintptr_t is that type, whether uintptr_t
is defined or not. My comments were meant to be taken relative
to the earlier suggestion, and interpreted in that light, not
as an independent statement.

What you wrote upthread was:

The only plausible choice for the pointer operand is uintptr_t
(or the moral equivalent in C90, etc), which will be wide enough
to represent the result so the right hand side cast could be
to that type.

The "in C90, etc" makes all the difference. In C99 and later, if
there is an unsigned integer type wide enough to hold a pointer,
then uintptr_t will exist (unless the implementation is perverse
enough that it omits uintptr_t unnecessarily). I didn't realize
until I searched upthread just now that pre-C99 implementations
were under discussion.

Oh, you must have missed it. It was present in both the postings
you responded to, and even in the quoted text (ie, not snipped)
in the first response you gave.
 

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
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top