Where do pointers point to?

X

x-pander

Is is guaranteed, that a pointer to any object in C points exactly at the
lowest addressed byte of this object?

Specifcally is it possible for any platform/os/compiler combination that:
(char *)v != (void *)v
where v is an int variable for example.

If so, any real-life examples?
 
B

Ben Pfaff

x-pander said:
Is is guaranteed, that a pointer to any object in C points exactly at the
lowest addressed byte of this object?

Yes, as far as I know. (I'd love to hear intelligent
disagreement on this, because I'd learn from it.)
Specifcally is it possible for any platform/os/compiler combination that:
(char *)v != (void *)v
where v is an int variable for example.

Non sequitur: you just dragged in integer-to-pointer conversion,
which is definitely non-portable.
 
X

x-pander

Specifcally is it possible for any platform/os/compiler combination that:
(char *)v != (void *)v
where v is an int variable for example.

CORRECTION, of course (!!!) i meant:
(char *)&v != (void *)&v
 
C

Christian Bau

"x-pander said:
Is is guaranteed, that a pointer to any object in C points exactly at the
lowest addressed byte of this object?

Specifcally is it possible for any platform/os/compiler combination that:
(char *)v != (void *)v
where v is an int variable for example.

A pointer points to the whole object.

If you cast a pointer to another type, lets say from double* to int*,
you get a pointer to an object that starts at the same place as the
first object. So if you cast a pointer to char*, it points to the first
byte of the object.

You cannot compare char* and void*. In your example, the compiler will
convert the (void *) v automatically to char*, so you are actually
comparing

(char *)v == (char *) (void *) v

which is guaranteed to be equal.
 
C

Christian Bau

Ben Pfaff said:
Yes, as far as I know. (I'd love to hear intelligent
disagreement on this, because I'd learn from it.)

It points to the "first" byte. The C Standard doesn't say anything about
addresses.

So if you have

int x;
char* p = (char *) &x;

then the bytes of x are p [0], p [1], ..., p [sizeof (int) - 1], and not
for example p [0], p [-1], p [-2] and so on.

However, imagine you have an application of 10 million lines of code,
non-portable because it is written under the assumption that your
hardware is bigendian. You need to make it run on littleendian hardware.
You have the source code to the compiler. Instead of changing 10 million
lines of code, change the compiler so that the "first" byte is at a
higher address than the last byte; where "p++;" would usually be
translated into a hardware instruction that adds sizeof (*p), it will be
translated to a hardware instruction that subtracts sizeof (*p). Pointer
comparisons say that p < q if a hardware compare instruction says p > q
and so on. Now a pointer always points to the highest addressed byte,
and it is completely conforming and invisible to the programmer. The
compiler turned a littleendian hardware into a bigendian implementation.
(Code that casts pointers to unsigned int and checks the last bits for
alignment will not work anymore; casting to and from integer will
generally give strange results).
 
X

x-pander

If you cast a pointer to another type, lets say from double* to int*,
you get a pointer to an object that starts at the same place as the
first object. So if you cast a pointer to char*, it points to the first
byte of the object.

I undesrtand that.
You cannot compare char* and void*. In your example, the compiler will
convert the (void *) v automatically to char*, so you are actually
comparing

(char *)v == (char *) (void *) v

which is guaranteed to be equal.

So how about the result of the following comparision,
which i think has a potential of effectively answering my original question:

(int *)(char *)&v != &v
 
K

Keith Thompson

Christian Bau said:
It points to the "first" byte. The C Standard doesn't say anything about
addresses.

Sure it does. Just one example, C99 6.5.3.1p3:

The unary & operator returns the address of its operand.
 
X

x-pander

It points to the "first" byte. The C Standard doesn't say anything about
addresses.

Actually it does:
C99: 6.3.2.3.7
"When a pointer to an object is converted to a pointer to a character type,
the result points to the lowest addressed byte of the object. Successive
increments of the result, up to the size of the object, yield pointers to
the remaining bytes of the object."
You need to make it run on littleendian hardware.
You have the source code to the compiler. Instead of changing 10 million
lines of code, change the compiler so that the "first" byte is at a
higher address than the last byte; where "p++;" would usually be
translated into a hardware instruction that adds sizeof (*p), it will be
translated to a hardware instruction that subtracts sizeof (*p). Pointer
comparisons say that p < q if a hardware compare instruction says p > q
and so on. Now a pointer always points to the highest addressed byte,
and it is completely conforming and invisible to the programmer.

An example situation in described system could be:

int x;
&x == 0x4003
(void *)&x == 0x4003
(char *)&x == 0x4000
(void *)(char *)&x = 0x4000

So:
(void *)&x != (void *)(char *)&x

In effect the following code would break (i've seen similar code in some
libraries):

void zero(void *ptr, int size)
{
memset(ptr, 0, size);
}
main()
{
int v;
zero(&v, sizeof(v));
}

The solution is to always use char * instead of void *.

Am I right?
 
X

x-pander

It points to the "first" byte. The C Standard doesn't say anything about
addresses.

Actually it does:
C99: 6.3.2.3.7
"When a pointer to an object is converted to a pointer to a character type,
the result points to the lowest addressed byte of the object. Successive
increments of the result, up to the size of the object, yield pointers to
the remaining bytes of the object."
You need to make it run on littleendian hardware.
You have the source code to the compiler. Instead of changing 10 million
lines of code, change the compiler so that the "first" byte is at a
higher address than the last byte; where "p++;" would usually be
translated into a hardware instruction that adds sizeof (*p), it will be
translated to a hardware instruction that subtracts sizeof (*p). Pointer
comparisons say that p < q if a hardware compare instruction says p > q
and so on. Now a pointer always points to the highest addressed byte,
and it is completely conforming and invisible to the programmer.

An example situation in described system could be:

int x;
&x == 0x4003
(void *)&x == 0x4003
(char *)&x == 0x4000
(void *)(char *)&x = 0x4000

So:
(void *)&x != (void *)(char *)&x

In effect the following code would break (i've seen similar code in some
libraries):

void zero(void *ptr, int size)
{
memset(ptr, 0, size);
}
main()
{
int v;
zero(&v, sizeof(v));
}

The solution is to always use char * instead of void *.

Am I right?
 
E

Eric Sosman

x-pander said:
So how about the result of the following comparision,
which i think has a potential of effectively answering my original question:

(int *)(char *)&v != &v

Guaranteed to work (evaluating to 0) if `v' is an `int'.

Potential undefined behavior if `v' is not an `int': the
conversion of any arbitrary (object) pointer to `char*' is
well-defined, but even so this does not justify the subsequent
attempt to convert a non-`int*' to an `int*'. There are a few
cases is which this is guaranteed to work (e.g., if `v' is a
struct whose first element is an `int'), but in general the
conversion is not safe.
 
L

Lawrence Kirby

A pointer points to the whole object.

Right. An example is a an implementation on a word addressed architecture.
Let's say int corresponds to the word size. A pointer to an int will point
to the whole word on that architecture, it is incapable of pointing at a
single byte. Additionally the implementation chooses to support bytes
smaller than words by generating extra code to select the appropriate bits
from the word. A character pointer therefore needs more information (i.e.
which "byte" within the word to select) and will typically be larger than
a word pointer, and a conversion between the two types of pointer will
require a change of representation.
If you cast a pointer to another type, lets say from double* to int*,
you get a pointer to an object that starts at the same place as the
first object.

That is likely but is not guaranteed. Taking the example above converting
a char * to an int * can't achieve this if the character pointer doesn't
point at a word boundary.
So if you cast a pointer to char*, it points to the first
byte of the object.

The standard has a specific rule that guarantees this when you convert to
pointers to character types, it isn't an example of a more general rule.
You cannot compare char* and void*. In your example, the compiler will
convert the (void *) v automatically to char*, so you are actually
comparing

The char * operand is converted to void *. It doesn't matter here but
is important for types other than pointers to characters.
(char *)v == (char *) (void *) v

which is guaranteed to be equal.

Yes, void * uses the same representation as pointers to character types.

Lawrence
 
C

Chris Croughton

Guaranteed to work (evaluating to 0) if `v' is an `int'.

Potential undefined behavior if `v' is not an `int': the
conversion of any arbitrary (object) pointer to `char*' is
well-defined, but even so this does not justify the subsequent
attempt to convert a non-`int*' to an `int*'. There are a few
cases is which this is guaranteed to work (e.g., if `v' is a
struct whose first element is an `int'), but in general the
conversion is not safe.

Am I correct in thinking that conversion of a T* to a char* is always
safe (because sizeof char <= sizeof T for all types T) but the other way
round may not be? For instance, an int* might be constrained to have
some bits zero, so conversion to an int* with those bits set might
either cause a hardware exception or 'silently' set the bits to zero.

Chris C
 
S

S.Tobias

Christian Bau said:
I'd say it's impossible to tell, unless you convert your pointer
to (char*), but then you're comparing different kind of pointers.
A pointer points to the whole object.
If you cast a pointer to another type, lets say from double* to int*,
you get a pointer to an object that starts at the same place as the
first object. So if you cast a pointer to char*, it points to the first
byte of the object.
You cannot compare char* and void*. In your example, the compiler will
convert the (void *) v automatically to char*, so you are actually
comparing

No, (char*)v will be implicitly converted to (void*) (cf. 6.5.9#5)
and void* pointers will be compared (although I can't see what possible
difference it might make which way we do the conversion - later, the
equality semantics doesn't depend on pointer type at all).
(char *)v == (char *) (void *) v
which is guaranteed to be equal.

int v;
(void*)(char*)&v == (void*)&v;

I still don't see it (maybe it's obvious, but it's still early morning
for me and a coffee didn't help). The Standard int 6.3.2.3 (Conversions ...
Pointers) only demands that (subject to alignment) conversions between
pointer types are reversible. However I don't see how you can infer
from it that single int*->void* conversion must yield the same value
as double conversion int*->char*->void*. How do you do it?

Where exactly is it written that the result of pointer conversion
(provided it doesn't invoke UB) must point to the same location
as the original pointer?
 
M

Michael Mair

Lawrence Kirby wrote:

[snip: void * vs char *]
Yes, void * uses the same representation as pointers to character types.

Are you sure of that? It is IMO logical but not necessary.

I am not sure where but a couple of months ago there was a
discussion where the example function execl() from the FAQ 5.2
( http://www.eskimo.com/~scs/C-faq/q5.2.html ) was cited and
where some regulars stressed how important the cast (char *)
is because execl is a function with variable argument list
and so we need to make sure that we get (char *) NULL instead
of plain (that is, (void *)) NULL.


Cheers
Michael
 
P

pete

Michael said:
Lawrence Kirby wrote:

[snip: void * vs char *]
Yes, void * uses the same representation
as pointers to character types.

Are you sure of that?

N869
6.2.5 Types

[#27] A pointer to void shall have the same representation
and alignment requirements as a pointer to a character type.
 
L

Lawrence Kirby

Lawrence Kirby wrote:

[snip: void * vs char *]
Yes, void * uses the same representation as pointers to character types.

Are you sure of that? It is IMO logical but not necessary.

6.2.5 says

"A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type."
I am not sure where but a couple of months ago there was a discussion
where the example function execl() from the FAQ 5.2 (
http://www.eskimo.com/~scs/C-faq/q5.2.html ) was cited and where some
regulars stressed how important the cast (char *) is because execl is a
function with variable argument list and so we need to make sure that we
get (char *) NULL instead of plain (that is, (void *)) NULL.

The case is important because NULL can be defined as, say, 0 i.e. have
an integer type. This is certainly not guaranteed in any sense to have any
representational equivalence to a pointer.

There is a footnote for the standard text above that says:

"The same representation and alignment requirements are meant to imply
interchangeability as arguments to functions, return values from
functions, and members of unions."

which brings up the question of whether you are guaranteed to be able to
pass a void * argument to a function that requires a char *. As the text
suggests you are pretty safe in doing this. OTOH the footnote is not
normative and the text of the standard makes no absolute guarantee.

Lawrence
 
E

Eric Sosman

Chris said:
Am I correct in thinking that conversion of a T* to a char* is always
safe (because sizeof char <= sizeof T for all types T) but the other way
round may not be? For instance, an int* might be constrained to have
some bits zero, so conversion to an int* with those bits set might
either cause a hardware exception or 'silently' set the bits to zero.

Converting `AnyData*' to `char*' (and back) is always safe,
but it's because the Standard says so, not because of the `sizeof'
relation. The Standard does not sanction the conversion of
`int*' to `short*', even when sizeof(short)<=sizeof(int). (I've
never encountered a system where this relation didn't hold or
where the conversion wouldn't work, but "There are more things
on Heaven and Earth" and my experience is non-infinite ...)
 
M

Michael Mair

Lawrence said:
Lawrence Kirby wrote:

[snip: void * vs char *]

Yes, void * uses the same representation as pointers to character types.

Are you sure of that? It is IMO logical but not necessary.


6.2.5 says

"A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type."

Thanks to you and pete :)

The case is important because NULL can be defined as, say, 0 i.e. have
an integer type. This is certainly not guaranteed in any sense to have any
representational equivalence to a pointer.

There is a footnote for the standard text above that says:

"The same representation and alignment requirements are meant to imply
interchangeability as arguments to functions, return values from
functions, and members of unions."

which brings up the question of whether you are guaranteed to be able to
pass a void * argument to a function that requires a char *. As the text
suggests you are pretty safe in doing this. OTOH the footnote is not
normative and the text of the standard makes no absolute guarantee.

Essentially, this makes void * a pointer to a character type but
for pointer arithmetics.
For the above mentioned execl() call I could also use a terminating
"(void *) 0" and be on the safe side.


Thank you for clarifying
Michael
 
C

CBFalconer

Lawrence said:
.... snip ...

which brings up the question of whether you are guaranteed to be
able to pass a void * argument to a function that requires a char *.
As the text suggests you are pretty safe in doing this. OTOH the
footnote is not normative and the text of the standard makes no
absolute guarantee.

You can pass a void* to a function requiring any form of pointer,
and the conversion is automatic. That is one of the points of
having the void* type.
 

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

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top