Discussion in 'C Programming' started by Stanley Rice, Sep 14, 2011.

1. ### Stanley RiceGuest

Hello all

I am confused of array and pointer these days, and wrote some testing
program. one of the snippet is as below:

int A[3];

printf("%p\n", A); // 1
printf("%p\n", &A); // 2
printf("%p\n", A + 1); // 3
printf("%p\n", &A + 1); // 4

It shows that the result of first and second statement is the same,
while the result of statement 3 and statement 4 is different. I can
understand the difference of result 3 and result 4, as if the pointer
to arrays are of different levels. But why the statement 1 and
statement 2 generate the same result?

What's more, when we initialize the pointer to a function. we can both
assign to the pointer with just a function name, as well as the
address of the function name, using &(ampersand) operator. Why we
could do so.

Stanley Rice, Sep 14, 2011

2. ### Ben BacarisseGuest

Stanley Rice <> writes:

> I am confused of array and pointer these days, and wrote some testing
> program. one of the snippet is as below:
>
> int A[3];
>
> printf("%p\n", A); // 1
> printf("%p\n", &A); // 2
> printf("%p\n", A + 1); // 3
> printf("%p\n", &A + 1); // 4
>
> It shows that the result of first and second statement is the same,
> while the result of statement 3 and statement 4 is different. I can
> understand the difference of result 3 and result 4, as if the pointer
> to arrays are of different levels. But why the statement 1 and
> statement 2 generate the same result?

Nit: convert the pointers to (void *) because that's what %p expects.
If you do that, 1 and 2 will always produce the same result no matter
what type the array has. I've used a machine where they won't always be
the same if the type of A is char[3].

The differences and potential differences come from the fact that A and
&A are different things. When an array is used in most contexts, it is
converted to a pointer to its first element. Being the operand of the
& operator is an exception to this rule. So in case 1, A is an 'int *'
and in case 2, &A is a pointer to the whole array (the type is
'int (*)[3]' if you are interested in the details).

On most systems, a pointer to the start of an array and a pointer to the
whole array will print the same using %p and they are guaranteed to be
the same when converted to a common type. I.e.

(void *)A == (void *)&A[0] && (void *)A == (void *)&A

is always true. The types are different and that means that they may
have different representations so %p might print different things for
in your unconverted printf calls (1 and 2).

The difference in 3 and 4 is due to the "levels" as you put it. Adding
to a pointer adds the size of the thing pointed to. A + 1 adds one to
an int * producing a pointer to A[1]. In fact, A[n] is defined to be
*(A + n). &A + 1 produces a pointer that points just past the end of
the array A.

I thought this might be FAQ (http://c-faq.com/) but I could not find the
-- it's good stuff.

> What's more, when we initialize the pointer to a function. we can both
> assign to the pointer with just a function name, as well as the
> address of the function name, using &(ampersand) operator. Why we
> could do so.

"Why" is never easy in C. That's just the way it is: the name of a
function is converted to a pointer to that function except when the
function name is the operand of &. Thus fname and &fname are always the
same thing.

--
Ben.

Ben Bacarisse, Sep 14, 2011

3. ### Paul NGuest

On Sep 14, 2:41 pm, Ben Bacarisse <> wrote:
> Stanley Rice <> writes:
> > I am confused of array and pointer these days, and wrote some testing
> > program. one of the snippet is as below:

>
> > int A[3];

>
> > printf("%p\n", A);          //   1
> > printf("%p\n", &A);         //   2
> > printf("%p\n", A + 1);      //   3
> > printf("%p\n", &A + 1);     //   4

>
> > It shows that the result of first and second statement is the same,
> > while the result of statement 3 and statement 4 is different. I can
> > understand the difference of result 3 and result 4, as if the pointer
> > to arrays are of different levels. But why the statement 1 and
> > statement 2 generate the same result?

(snip)

> I thought this might be FAQ (http://c-faq.com/) but I could not find the
> -- it's good stuff.

Yes, 6.12 is the one. Though I managed to miss it too, and only found
it by remembering the wording and using Google!

Paul N, Sep 14, 2011
4. ### Peter NilssonGuest

Ben Bacarisse <> wrote:
> Stanley Rice <> writes:
> > int A[3];
> >
> > printf("%p\n", A); // 1
> > printf("%p\n", &A); // 2
> > printf("%p\n", A + 1); // 3
> > printf("%p\n", &A + 1); // 4

<snip>
>
> Nit: convert the pointers to (void *) because that's what %p
> expects.

True.

> If you do that, 1 and 2 will always produce the same result no
> matter what type the array has.

That's not true. If the OP wants to know if they compare equal,
then the equality operater should be used. There is no guarantee
that %p prints exactly the same thing, even for pointer arguments
with the same representation. [e.g segmented architectures.]

The only guarantee is that if you read the output with scanf (et
al,) the conversion will compare equal with the original pointer

<snip>

--
Peter

Peter Nilsson, Sep 15, 2011
5. ### Ben BacarisseGuest

Peter Nilsson <> writes:

> Ben Bacarisse <> wrote:
>> Stanley Rice <> writes:
>> > int A[3];
>> >
>> > printf("%p\n", A); // 1
>> > printf("%p\n", &A); // 2
>> > printf("%p\n", A + 1); // 3
>> > printf("%p\n", &A + 1); // 4

> <snip>
>>
>> Nit: convert the pointers to (void *) because that's what %p
>> expects.

>
> True.
>
>> If you do that, 1 and 2 will always produce the same result no
>> matter what type the array has.

>
> That's not true. If the OP wants to know if they compare equal,
> then the equality operater should be used. There is no guarantee
> that %p prints exactly the same thing, even for pointer arguments
> with the same representation. [e.g segmented architectures.]

Good point. Once converted the pointers will compare equal but even
equal pointers might print differently.

<snip>
--
Ben.

Ben Bacarisse, Sep 15, 2011
6. ### Stanley RiceGuest

On Sep 14, 9:41 pm, Ben Bacarisse <> wrote:
> Stanley Rice <> writes:
> > I am confused of array and pointer these days, and wrote some testing
> > program. one of the snippet is as below:

>
> > int A[3];

>
> > printf("%p\n", A);          //   1
> > printf("%p\n", &A);         //   2
> > printf("%p\n", A + 1);      //   3
> > printf("%p\n", &A + 1);     //   4

>
> > It shows that the result of first and second statement is the same,
> > while the result of statement 3 and statement 4 is different. I can
> > understand the difference of result 3 and result 4, as if the pointer
> > to arrays are of different levels. But why the statement 1 and
> > statement 2 generate the same result?

>
> Nit: convert the pointers to (void *) because that's what %p expects.
> If you do that, 1 and 2 will always produce the same result no matter
> what type the array has.  I've used a machine where they won't always be
> the same if the type of A is char[3].
>
> The differences and potential differences come from the fact that A and
> &A are different things.  When an array is used in most contexts, it is
> converted to a pointer to its first element.  Being the operand of the
> & operator is an exception to this rule.  So in case 1, A is an 'int *'
> and in case 2, &A is a pointer to the whole array (the type is
> 'int (*)[3]' if you are interested in the details).
>
> On most systems, a pointer to the start of an array and a pointer to the
> whole array will print the same using %p and they are guaranteed to be
> the same when converted to a common type.  I.e.
>
>   (void *)A == (void *)&A[0] && (void *)A == (void *)&A
>
> is always true.  The types are different and that means that they may
> have different representations so %p might print different things for
> in your unconverted printf calls (1 and 2).
>
> The difference in 3 and 4 is due to the "levels" as you put it.  Adding
> to a pointer adds the size of the thing pointed to.  A + 1 adds one to
> an int * producing a pointer to A[1].  In fact, A[n] is defined to be
> *(A + n).  &A + 1 produces a pointer that points just past the end of
> the array A.
>
> I thought this might be FAQ (http://c-faq.com/) but I could not find the
> -- it's good stuff.
>
> > What's more, when we initialize the pointer to a function. we can both
> > assign to the pointer with just a function name, as well as the
> > address of the function name, using &(ampersand) operator. Why we
> > could do so.

>

(snip)
> "Why" is never easy in C.  That's just the way it is: the name of a
> function is converted to a pointer to that function except when the
> function name is the operand of &.  Thus fname and &fname are always the
> same thing.

So What you mean is that the compiler does most of things for us? I
have tried to compare the address of function, say

void foo() { }

assert((void *)foo == (void *)&foo);

and it passes. Is it the reason as the issue of the array talk above ?

Stanley Rice, Sep 15, 2011
7. ### Stanley RiceGuest

On Sep 15, 5:54 pm, Ben Bacarisse <> wrote:
> Peter Nilsson <> writes:
> > Ben Bacarisse <> wrote:
> >> Stanley Rice <> writes:
> >> > int A[3];

>
> >> > printf("%p\n", A);          //   1
> >> > printf("%p\n", &A);         //   2
> >> > printf("%p\n", A + 1);      //   3
> >> > printf("%p\n", &A + 1);     //   4

> > <snip>

>
> >> Nit: convert the pointers to (void *) because that's what %p
> >> expects.

>
> > True.

>
> >> If you do that, 1 and 2 will always produce the same result no
> >> matter what type the array has.

>
> > That's not true. If the OP wants to know if they compare equal,
> > then the equality operater should be used. There is no guarantee
> > that %p prints exactly the same thing, even for pointer arguments
> > with the same representation. [e.g segmented architectures.]

<snip>
> Good point.  Once converted the pointers will compare equal but even
> equal pointers might print differently.

Thanks for you replying. But I am sorry that I am not fully understand
that.

1. when we use %p to print the pointer, but the argument is not
explicitly converted, will it implicitly be converted to (void *)
type?
2. Why the equal pointers will print differently? It's machine
dependent or anything else? Can we say that, two pointers must be
equal if they are printed the same.
3. In my previous post. If I change my code:
printf("the address of A+1: %p\n", (void *)A+1); // 3'
printf("the address of &A+1: %p\n", (void *)&A+1); // 4'

statement 3' and 4' will print the same thing. Why it that compared to
my original code, without explicitly cast.

Stanley Rice, Sep 15, 2011
8. ### Ike NaarGuest

On 2011-09-15, Stanley Rice <> wrote:
> 1. when we use %p to print the pointer, but the argument is not
> explicitly converted, will it implicitly be converted to (void *)
> type?

No.

> 2. Why the equal pointers will print differently? It's machine
> dependent or anything else? Can we say that, two pointers must be
> equal if they are printed the same.

Imagine a cpu architecture where pointers are represented by a pair
(base,offset) where the effective memory address is obtained by

address = 16 * base + offset

The pointer (2,25) represents effective memory address 16 * 2 * 25 = 57 .
The pointer (3,9) represents effective memory address 16 * 3 + 9 = 57 .
These two pointers could print differently (say, "2:25" vs. "3:9") but
compare equal (57 vs. 57).

> 3. In my previous post. If I change my code:
> printf("the address of A+1: %p\n", (void *)A+1); // 3'
> printf("the address of &A+1: %p\n", (void *)&A+1); // 4'

Beware: (void *)A+1 is parsed as ((void *)A) + 1 which is
not correct C (one cannot perform arithmetic on a pointer to void)
although gcc will probably accept it as an extension.

You probably meant (void *) (A+1)

Ike Naar, Sep 15, 2011
9. ### NobodyGuest

On Thu, 15 Sep 2011 05:36:48 -0700, Stanley Rice wrote:

> 1. when we use %p to print the pointer, but the argument is not
> explicitly converted, will it implicitly be converted to (void *)
> type?

No. The compiler doesn't know the types of printf's arguments (other than
the first one), so it can't know that it should be a void*.

> 2. Why the equal pointers will print differently? It's machine
> dependent or anything else?

The format used by "%p" is implementation-dependent.

One reason why equal pointers might print differently is if there are
multiple representations which are considered equal, and the output for
"%p" is based upon the representation without any form of normalisation.

E.g. on 8086, a (far) pointer contains a 16-bit segment and a 16-bit
offset. The actual memory address is "segment * 16 + offset", so e.g.
0100:2300 and 0200:1300 both refer to the address 0x03300. If
comparison normalises the pointers, they will compare equal. If printing
uses the raw representation, they will print differently.

> Can we say that, two pointers must be equal if they are printed the same.

No. The format used by "%p" is implementation-dependent. An
implementation is free to print e.g. "?" for every pointer.

> 3. In my previous post. If I change my code:
> printf("the address of A+1: %p\n", (void *)A+1); // 3'
> printf("the address of &A+1: %p\n", (void *)&A+1); // 4'
>
> statement 3' and 4' will print the same thing. Why it that compared to
> my original code, without explicitly cast.

You're relying upon a implementation-specific extension. Type casts bind
more tightly than addition, so "(void *)A+1" is parsed as "((void *)A)+1".
This is invalid according to the standard ("void" doesn't have a size, so
you can't perform arithmetic on a "void*").

Implementations which allow arithmetic on void* (e.g. gcc) act as if
sizeof(void)==1 in such cases. Because you convert before adding, both
expressions have the same value.

The reason why the original expressions had different values is that, in
pointer arithmetic, the offset is the number of items rather than the
number of bytes, so the calculation scales the offset by the size of the
type being pointed to.

So "A+1" is one int past A ("A" is a pointer to int) while "&A+1" is one
array of 3 ints past A ("&A" is a pointer to an array of 3 ints).

To correctly apply an explicit cast to your original code, you should have
written:

printf("the address of A+1: %p\n", (void *)(A+1)); // 3'
printf("the address of &A+1: %p\n", (void *)(&A+1)); // 4'

This will (typically) produce the same result as before, except that this
version doesn't rely upon implementation-specific behavior (i.e. all
pointers using the same representation).

Nobody, Sep 15, 2011
10. ### James KuyperGuest

On 09/15/2011 08:36 AM, Stanley Rice wrote:
....
> 1. when we use %p to print the pointer, but the argument is not
> explicitly converted, will it implicitly be converted to (void *)
> type?

No, and that's what makes the behavior undefined. That's because
printf() accepts a variable list of arguments. For the variable part of
it's argument list, the only implicit conversions that occur are the
default argument promotions.

> 2. Why the equal pointers will print differently? It's machine
> dependent or anything else? Can we say that, two pointers must be
> equal if they are printed the same.

As a general rule, what's printed by the printf("%p, ... ) is related to
the representation of a pointer. The standard does not require that
pointers pointing to the same location have the same representation,
only that they must compare equal. Real implementations have used
representations for which such a requirement would be a problem. I've
used machines where addresses were represented by a 16-bit segment and a
16-bit offset, and the physical address was 16*segment+offset, so that
there were a great many different ways of forming pointers with
different representations that point at the same location.

Yes, it is machine dependent. In principle, even different
implementations for the same machine could implement pointers
differently, but that's rather unlikely.

I believe that two pointers that print the same must compare equal; but
not vice-versa.

> 3. In my previous post. If I change my code:
> printf("the address of A+1: %p\n", (void *)A+1); // 3'
> printf("the address of &A+1: %p\n", (void *)&A+1); // 4'
>
> statement 3' and 4' will print the same thing. Why it that compared to
> my original code, without explicitly cast.

(void*)A+1 is a constraint violation, because (void*)A is a pointer, and
is not a pointer to an object type. Many compilers operate, by default,
in a non-conforming mode that allows such expressions. They treat it as
the rough equivalent of (void*)((char*)A + 1). Since A and &A are
pointers of different types that point at the same location.
(void*)((char*)&A + 1) points at the same location a (void*)((char*)A +
1), which is why the results you got were the same.

If your compiler allows such code, find out if you can disable that
"feature". For instance, with gcc, use "-Wpointer-arith". It represents
a fundamental misconception of what void* means to allow pointer
arithmetic on void*. Before the inventions of void*, char* was used for
the same purpose. void* was invented specifically to indicate that your
code is NOT keeping track of what type of thing the pointer points at.
It differs from char* in two important ways. The first way is that
pointers to other object types convert to and from void* implicitly,
which greatly simplifies typical uses of void*.

The second way, and the one that is relevant here, is that it is a
constraint violation to use a pointer to void in any context that
requires knowledge of the type of object that the pointer points at. In
particular, if p is a pointer to an object type, and n is an integer,
the value of p+n points at a location that is farther along in memory by
exactly enough space for n objects of the type that p points at. In
other words, (char*)(p+n) = (char*)p + n*sizeof *p. However, if p is a
pointer to void, there is NO type type p points at. sizeof *p and
sizeof(void) both constraint violations, as is p+n. If you don't want to
get diagnostic messages as a result of writing code like p+1, you should
make sure that p is a pointer to an object type, such as char*, not a
pointer to void.

James Kuyper, Sep 15, 2011
11. ### James KuyperGuest

On 09/15/2011 08:22 AM, Stanley Rice wrote:
> On Sep 14, 9:41 pm, Ben Bacarisse <> wrote:
>> Stanley Rice <> writes:

....
>>> What's more, when we initialize the pointer to a function. we can both
>>> assign to the pointer with just a function name, as well as the
>>> address of the function name, using &(ampersand) operator. Why we
>>> could do so.

>>

> (snip)
>> "Why" is never easy in C. That's just the way it is: the name of a
>> function is converted to a pointer to that function except when the
>> function name is the operand of &. Thus fname and &fname are always the
>> same thing.

> So What you mean is that the compiler does most of things for us? I
> have tried to compare the address of function, say
>
> void foo() { }
>
> assert((void *)foo == (void *)&foo);
>
> and it passes. Is it the reason as the issue of the array talk above ?

No, the rule for arrays doesn't apply here. However, as he said above,
there is a similar rule for functions, and that is what makes this code
work.

James Kuyper, Sep 15, 2011
12. ### Keith ThompsonGuest

Nobody <> writes:
> On Thu, 15 Sep 2011 05:36:48 -0700, Stanley Rice wrote:

[...]
>> Can we say that, two pointers must be equal if they are printed the same.

>
> No.

Yes.

> The format used by "%p" is implementation-dependent.

Correct.

> An
> implementation is free to print e.g. "?" for every pointer.

No, it isn't. The string printed by printf with "%p" must be readable
by scanf with "%p", and the result from scanf must compare equal to the
original pointer.

[...]

--
Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson, Sep 15, 2011
13. ### Keith ThompsonGuest

Stanley Rice <> writes:
[...]
> So What you mean is that the compiler does most of things for us? I
> have tried to compare the address of function, say
>
> void foo() { }
>
> assert((void *)foo == (void *)&foo);
>
> and it passes. Is it the reason as the issue of the array talk above ?

That's not guaranteed to work. The behavior of converting a function
pointer to void* is not defined.

It's likely to work in practice (and I think POSIX requires it
to work), but there have been systems where function pointers are
bigger than void*, so the conversion could lose information.

--
Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson, Sep 15, 2011
14. ### Stanley RiceGuest

On Sep 16, 3:26 am, pete <> wrote:
> James Kuyper wrote:
>
> > On 09/15/2011 08:22 AM, Stanley Rice wrote:
> > > So What you mean is that the compiler does most of things for us? I
> > > have tried to compare the address of function, say

>
> > > void foo() { }

>
> > > assert((void *)foo == (void *)&foo);

>
> > > and it passes. Is it the reason as the issue of the array talk above ?

>
> > No, the rule for arrays doesn't apply here. However, as he said above,
> > there is a similar rule for functions,
> > and that is what makes this code work.

>
> That code would be fine without the casts,
>
>     assert(foo == &foo);
>
> but
> the result of a pointer to a function
> being cast to a pointer to an incomplete type such as (void *),
> is undefined.
>
> --
> pete

Err, I seems that I am just a novice and I don't fully understand the
pointer. Why should a pointer have to an object that has a specific
type, even,(void). Every code and variable and anything else just
store in the memory. Does the pointer with the specific type to point
to locate how much memory space to charge?

For example, a pointer points to type int means that 4 bytes of memory
is in the charge of the pointer, and a pointer points to type char
means that 1 byte of memory is in the charge of the pointer. In this
way, when we dereference a pointer that points to type int, we can get
a 4 byte integer, and when we dereference a pointer to char, we can
get one byte character. Is that right? And I wrote a testing program,
the snippet is as below:

int a = 48; // 48 represents character '0' in ASCII
int *b = &a;
char *c = (char *)b;
printf("%c\n", c); //2

The printf statement prints the character '0'. I guess the reason is
that,according to the little-endian priciple, integer 48 stores in the
side of least significant bit, but its memory address is lowest. When
I cast pointer b explicitly with (char *) to pointer c that points to
a char. The new pointer c, points to the original address where b ever
points to, but the difference is that, the pointer c that points to a
char can only in charge of one byte, that is, the lowest byte. so, '0'
is printed.

To prove my assumption, I try to change my code, In the first
statement, I change integer 48 to 304 (304 = 256 + 48), the least
sinificant byte is still hold integer 48, but the second least
significant byte hold an integer 1. In this way, the printf statement
still print character '0'.

So I guess the use of pointer pointed type is to determine how many
byte could this pointer in charge from the least significant byte. But
I don't know whether I'm right or not.

If my assumption is correct, then may be I can guess why casting a
pointer to function to void* is undefined. The pointer points to the
starting address of the function, without knowing the whole length of
the function, so the pointer doesn't know how many bytes could the
pointer in charge of, right?

Stanley Rice, Sep 16, 2011
15. ### Stanley RiceGuest

On Sep 16, 2:51 am, Keith Thompson <> wrote:
> Stanley Rice <> writes:
>
> [...]
>
> > So What you mean is that the compiler does most of things for us? I
> > have tried to compare the address of function, say

>
> > void foo() { }

>
> > assert((void *)foo == (void *)&foo);

>
> > and it passes. Is it the reason as the issue of the array talk above ?

>
> That's not guaranteed to work.  The behavior of converting a function
> pointer to void* is not defined.

<snip>
> It's likely to work in practice (and I think POSIX requires it
> to work), but there have been systems where function pointers are
> bigger than void*, so the conversion could lose information.

I am not fully understand your meaning of "function pointers are
bigger than void *". I know it's not the size of the pointer. Do you
mean that how many bytes the pointer can in charge of? i.e. a pointer
points to int can in charge of 4 bytes and a pointer points to double
can in charge of 8 bytes, where a pointer to void can only in charge
of 1 byte.

Stanley Rice, Sep 16, 2011
16. ### Stanley RiceGuest

On Sep 16, 3:26 am, pete <> wrote:
> James Kuyper wrote:
>
> > On 09/15/2011 08:22 AM, Stanley Rice wrote:
> > > So What you mean is that the compiler does most of things for us? I
> > > have tried to compare the address of function, say

>
> > > void foo() { }

>
> > > assert((void *)foo == (void *)&foo);

>
> > > and it passes. Is it the reason as the issue of the array talk above ?

>
> > No, the rule for arrays doesn't apply here. However, as he said above,
> > there is a similar rule for functions,
> > and that is what makes this code work.

>
> That code would be fine without the casts,
>
>     assert(foo == &foo);
>
> but
> the result of a pointer to a function
> being cast to a pointer to an incomplete type such as (void *),
> is undefined.
>
> --
> pete

Err, I seems that I am just a novice and I don't fully understand the
pointer. Why should a pointer have to an object that has a specific
type, even,(void). Every code and variable and anything else just
store in the memory. Does the pointer with the specific type to point
to locate how much memory space to charge?

For example, a pointer points to type int means that 4 bytes of memory
is in the charge of the pointer, and a pointer points to type char
means that 1 byte of memory is in the charge of the pointer. In this
way, when we dereference a pointer that points to type int, we can get
a 4 byte integer, and when we dereference a pointer to char, we can
get one byte character. Is that right? And I wrote a testing program,
the snippet is as below:

int a = 48; // 48 represents character '0' in ASCII
int *b = &a;
char *c = (char *)b;
printf("%c\n", c); //2

The printf statement prints the character '0'. I guess the reason is
that,according to the little-endian priciple, integer 48 stores in the
side of least significant bit, but its memory address is lowest. When
I cast pointer b explicitly with (char *) to pointer c that points to
a char. The new pointer c, points to the original address where b ever
points to, but the difference is that, the pointer c that points to a
char can only in charge of one byte, that is, the lowest byte. so, '0'
is printed.

To prove my assumption, I try to change my code, In the first
statement, I change integer 48 to 304 (304 = 256 + 48), the least
sinificant byte is still hold integer 48, but the second least
significant byte hold an integer 1. In this way, the printf statement
still print character '0'.

So I guess the use of pointer pointed type is to determine how many
byte could this pointer in charge from the least significant byte. But
I don't know whether I'm right or not.

If my assumption is correct, then may be I can guess why casting a
pointer to function to void* is undefined. The pointer points to the
starting address of the function, without knowing the whole length of
the function, so the pointer doesn't know how many bytes could the
pointer in charge of, right?

Stanley Rice, Sep 16, 2011
17. ### James KuyperGuest

On 09/15/2011 09:13 PM, Stanley Rice wrote:
> On Sep 16, 2:51ï¿½am, Keith Thompson <> wrote:

....
>> It's likely to work in practice (and I think POSIX requires it
>> to work), but there have been systems where function pointers are
>> bigger than void*, so the conversion could lose information.

>
> I am not fully understand your meaning of "function pointers are
> bigger than void *". I know it's not the size of the pointer.

You "know" incorrectly. Function pointers can have a size that is
different from the size of void*, and there have been many systems where
this is indeed the case.
--
James Kuyper

James Kuyper, Sep 16, 2011
18. ### Stanley RiceGuest

<snip>
> >> Can we say that, two pointers must be equal if they are printed the same.

>
> > No.

>
> Yes.

How to print the address of a pointer is implementation dependant,
based on how to represent the pointer. Now I can understand two
pointers point to the same memory location may print differently.

But is it possible that two different pointers that point two
"Once converted the pointers will compare equal but even equal
pointers might print differently"

Stanley Rice, Sep 16, 2011
19. ### Keith ThompsonGuest

Stanley Rice <> writes:
> On Sep 16, 3:26Â am, pete <> wrote:
>> James Kuyper wrote:
>>
>> > On 09/15/2011 08:22 AM, Stanley Rice wrote:
>> > > So What you mean is that the compiler does most of things for us? I
>> > > have tried to compare the address of function, say

>>
>> > > void foo() { }

>>
>> > > assert((void *)foo == (void *)&foo);

>>
>> > > and it passes. Is it the reason as the issue of the array talk above ?

>>
>> > No, the rule for arrays doesn't apply here. However, as he said above,
>> > there is a similar rule for functions,
>> > and that is what makes this code work.

>>
>> That code would be fine without the casts,
>>
>> Â  Â  assert(foo == &foo);
>>
>> but
>> the result of a pointer to a function
>> being cast to a pointer to an incomplete type such as (void *),
>> is undefined.
>>
>> --
>> pete

>
> Err, I seems that I am just a novice and I don't fully understand the
> pointer. Why should a pointer have to an object that has a specific
> type, even,(void). Every code and variable and anything else just
> store in the memory. Does the pointer with the specific type to point
> to locate how much memory space to charge?

The type of a pointer is generally a compile-time concept. For example,
given:

short *p1;
double *p2;

p1 and p2 *might* have the same size and representation, but they're of
different types. That means, among other things, that the expression
``*p1'' is of type short, the expression ``*p2'' is of type double, and
the assignment ``p1 = p2'' is invalid, since the types are incompatible.
(I'm not using the term "incompatible" quite the same way the standard
does.)

And consider a system where int and long have exactly the same size and
representation (say they're both 4 bytes). int* and long* are still two
distinct types, and the compiler won't allow you to assign one to the
other without a cast (or at least it will warn you if you attempt to do
so). There's more to type than size.

> For example, a pointer points to type int means that 4 bytes of memory
> is in the charge of the pointer, and a pointer points to type char
> means that 1 byte of memory is in the charge of the pointer.

Pretty much, though I'm not sure what "in the charge of" means
here. Also, an int isn't necessarily 4 bytes, though a char is by
definition 1 byte (but a byte can be more than 8 bits).

> In this
> way, when we dereference a pointer that points to type int, we can get
> a 4 byte integer, and when we dereference a pointer to char, we can
> get one byte character. Is that right? And I wrote a testing program,
> the snippet is as below:
>
> int a = 48; // 48 represents character '0' in ASCII

ASCII is not the only character set; this would be better written as
int a = '0';

> int *b = &a;
> char *c = (char *)b;

This is not reliable. It causes c to point to the first byte of a;
that's not necessarily the low-order byte.

> printf("%c\n", c); //2

I think you meant

printf("%c\n", *c);

> The printf statement prints the character '0'. I guess the reason is
> that,according to the little-endian priciple, integer 48 stores in the
> side of least significant bit, but its memory address is lowest. When
> I cast pointer b explicitly with (char *) to pointer c that points to
> a char. The new pointer c, points to the original address where b ever
> points to, but the difference is that, the pointer c that points to a
> char can only in charge of one byte, that is, the lowest byte. so, '0'
> is printed.

Yes, but little-endianness is not a principle, it's merely an
implementation choice.

> To prove my assumption, I try to change my code, In the first
> statement, I change integer 48 to 304 (304 = 256 + 48), the least
> sinificant byte is still hold integer 48, but the second least
> significant byte hold an integer 1. In this way, the printf statement
> still print character '0'.
>
> So I guess the use of pointer pointed type is to determine how many
> byte could this pointer in charge from the least significant byte. But
> I don't know whether I'm right or not.

It's the lowest addressed byte, not necessarily the least significant
byte.

> If my assumption is correct, then may be I can guess why casting a
> pointer to function to void* is undefined. The pointer points to the
> starting address of the function, without knowing the whole length of
> the function, so the pointer doesn't know how many bytes could the
> pointer in charge of, right?

A function pointer isn't necessarily the memory address of the start
of the function. On most systems you're likely to use, it probably
will be, but the standard doesn't guarantee it. For example, it
could be an index into a table of all the functions in your program.
Or it could contain additional system-specific information. (As I
recall, function pointers on the IBM AS/400 are something like
16 bytes, though it's very likely I've got the details wrong.)
The standard only requires that function pointers work the way
they're supposed to: you can call functions through them, distinct
functions have distinct addresses, and so on.

Conversion from a function pointer to void* is undefined simply
because the standard doesn't define it -- and the reason for that
is that any definition could make a correct implementation difficult
or impossible on some systems.

--
Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson, Sep 16, 2011
20. ### Ben BacarisseGuest

Stanley Rice <> writes:

> <snip>
>> >> Can we say that, two pointers must be equal if they are printed the same.

>>
>> > No.

>>
>> Yes.

> How to print the address of a pointer is implementation dependant,
> based on how to represent the pointer. Now I can understand two
> pointers point to the same memory location may print differently.

Yup.

> But is it possible that two different pointers that point two
> different address print the same.

No. The only restriction on what %p produces is that it can be used to
recover the address if read back in using one of the scanf functions.
If two unequal pointers "printed the same" they'd read the same and that
is not permitted.

> Just as Ben Bacarisse ever reply
> "Once converted the pointers will compare equal but even equal
> pointers might print differently"