Address of array && address of pointer to array

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

  1. Stanley Rice

    Stanley Rice Guest

    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.

    Thanks for answering.
     
    Stanley Rice, Sep 14, 2011
    #1
    1. Advertising

  2. 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
    right answer there . Even so, read section 6 about arrays and pointers
    -- 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
    #2
    1. Advertising

  3. Stanley Rice

    Paul N Guest

    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
    > right answer there .  Even so, read section 6 about arrays and pointers
    > -- 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
    #3
  4. 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
    (if its lifetime hasn't expired.)

    <snip>

    --
    Peter
     
    Peter Nilsson, Sep 15, 2011
    #4
  5. 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
    #5
  6. Stanley Rice

    Stanley Rice Guest

    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
    > right answer there .  Even so, read section 6 about arrays and pointers
    > -- 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
    #6
  7. Stanley Rice

    Stanley Rice Guest

    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
    #7
  8. Stanley Rice

    Ike Naar Guest

    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
    #8
  9. Stanley Rice

    Nobody Guest

    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
    #9
  10. Stanley Rice

    James Kuyper Guest

    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
    #10
  11. Stanley Rice

    James Kuyper Guest

    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
    #11
  12. 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
    #12
  13. 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
    #13
  14. Stanley Rice

    Stanley Rice Guest

    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
    #14
  15. Stanley Rice

    Stanley Rice Guest

    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
    #15
  16. Stanley Rice

    Stanley Rice Guest

    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
    #16
  17. Stanley Rice

    James Kuyper Guest

    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
    #17
  18. Stanley Rice

    Stanley Rice Guest

    <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
    different address print the same. Just as Ben Bacarisse ever reply
    "Once converted the pointers will compare equal but even equal
    pointers might print differently"
     
    Stanley Rice, Sep 16, 2011
    #18
  19. 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
    #19
  20. 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"


    I am not sure what your point is about this quote from me. What it says
    is very similar to the second sentence of your first paragraph

    --
    Ben.
     
    Ben Bacarisse, Sep 16, 2011
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    10
    Views:
    742
    Chris Torek
    Feb 4, 2005
  2. jimjim
    Replies:
    16
    Views:
    876
    Jordan Abel
    Mar 28, 2006
  3. Scott
    Replies:
    6
    Views:
    397
    Luke Meyers
    Mar 27, 2006
  4. , India

    pointer to an array vs pointer to pointer

    , India, Sep 20, 2011, in forum: C Programming
    Replies:
    5
    Views:
    497
    James Kuyper
    Sep 23, 2011
  5. junyangzou
    Replies:
    8
    Views:
    196
    junyangzou
    Aug 30, 2013
Loading...

Share This Page