Once again pointer to first element vs pointer to array cast topointer to element

Discussion in 'C Programming' started by Szabolcs Borsanyi, May 7, 2008.

  1. I know that this topic has been discussed a lot, still I'd appreciate
    a clear cut (and correct) answer:
    I pass a multidimensional array to a function, which is defined as
    int f(int a[10][10])
    {
    int *b=(void*)a;
    int *c=a[0];
    /*...*/
    }
    Now the questions come:
    - Is it guaranteed that b and c points to the same object (or is this
    implementation defined)?
    - Is it always true that a[1][1] refers to the same object as c[11] ?
    (There is no hole)
    - Does dereferencing b violate any aliasing rule?

    Thanks
    Szabolcs
     
    Szabolcs Borsanyi, May 7, 2008
    #1
    1. Advertising

  2. Re: Once again pointer to first element vs pointer to array cast to pointer to element

    On Tue, 6 May 2008 23:46:56 -0700 (PDT), Szabolcs Borsanyi
    <-heidelberg.de> wrote:

    >I know that this topic has been discussed a lot, still I'd appreciate
    >a clear cut (and correct) answer:
    >I pass a multidimensional array to a function, which is defined as
    >int f(int a[10][10])
    >{
    > int *b=(void*)a;
    > int *c=a[0];
    > /*...*/
    >}
    >Now the questions come:
    >- Is it guaranteed that b and c points to the same object (or is this
    >implementation defined)?


    It is true that a, a[0], and a[0][0] all start at the same address, to
    be called THE ADDRESS below.

    In your first assignment, the expression a is converted by the
    compiler to the value and type of &a[0]. You then cast this to void*
    and then implicitly convert it to an int*. Since the value (address)
    is properly aligned for an int, everything is well defined and you end
    with THE ADDRESS in the form of an int*.

    In your second assignment, the expression a[0] is converted to the
    value and type of &a[0][0] which is already an int* and assigned to an
    int* with no conversion needed. You also end up with THE ADDRESS in
    the form of an int*.

    So b and c point to the same address and treat that address as the
    address of an int. The answer to your question is yes they do and no
    it is not implementation defined but a standard part of the language.

    >- Is it always true that a[1][1] refers to the same object as c[11] ?
    >(There is no hole)


    This is one for the language lawyers. Does c[11] (or even c[10])
    exist from a purist point of view. There has been plenty of
    discussion previously in this group. As a practical matter, I don't
    believe anyone has identified a system where it doesn't work.

    >- Does dereferencing b violate any aliasing rule?


    Dereferencing b results in an int. Since b does in fact point to an
    int there is no conflict. See section 6.5-7.


    Remove del for email
     
    Barry Schwarz, May 8, 2008
    #2
    1. Advertising

  3. Re: Once again pointer to first element vs pointer to array cast to pointer to element

    On Tue, 6 May 2008 23:46:56 -0700 (PDT), Szabolcs Borsanyi
    <-heidelberg.de> wrote:

    > I know that this topic has been discussed a lot, still I'd appreciate
    > a clear cut (and correct) answer:
    > I pass a multidimensional array to a function, which is defined as
    > int f(int a[10][10])


    Just to be clear, I assume you understand this actually declares a the
    same type as int (*a) [10] . The C language allows you to pass e.g.
    x[N][10] for any N (>0) as the argument to this parameter, and access
    a[j] for i up to N and j up to 10 exclusive.

    > {
    > int *b=(void*)a;
    > int *c=a[0];
    > /*...*/
    > }
    > Now the questions come:
    > - Is it guaranteed that b and c points to the same object (or is this
    > implementation defined)?


    They're guaranteed to point to the same (one) int. It is theoretically
    arguable how many of the following int's they can access; see below.

    > - Is it always true that a[1][1] refers to the same object as c[11] ?
    > (There is no hole)


    It is guaranteed there is no hole between array elements, at any
    level; thus a[0][0] is followed immediately by a[0][1], and a[0] as a
    whole is followed immediately by a[1] as a whole, therefore a[0][9] is
    followed immediately by a[1][0].

    And so it is guaranteed &a[0][10] == &a[1][0]. And, for example,
    memcpy (tempi, (char*)a + 12*sizeof(int), sizeof(int))
    will get you the value of a[1][2], and the reverse will set it.

    According to the strict abstract semantics, you can't dereference
    &a[0][10] and can't form &a[0][11] or higher at all. I believe that in
    these strict abstract semantics the pointer you store into c _may_
    retain this limitation, and thus c[10] and c[11] etc. might not work.
    However, I don't know of, and to my knowledge no one has posted about,
    any compiler that actually tries to do this. In practice, accessing 2D
    (or higher) as 1D row-major works, and so much existing code assumes
    this no sane C implementor will break it without very good reason.

    > - Does dereferencing b violate any aliasing rule?
    >

    *b for a[0][0] is definitely OK, but I assume you are actually
    concerned with more like b[12]. As above, it's not absolutely clear
    how much of a (or the argument e.g. x) you are strictly guaranteed
    able to access through the 'voided' b. In practice it will be all.

    - formerly david.thompson1 || achar(64) || worldnet.att.net
     
    David Thompson, May 19, 2008
    #3
  4. On May 19, 4:59 am, David Thompson <> wrote:
    > On Tue, 6 May 2008 23:46:56 -0700 (PDT), Szabolcs Borsanyi
    >
    > <-heidelberg.de> wrote:
    > > I know that this topic has been discussed a lot, still I'd appreciate
    > > a clear cut (and correct) answer:
    > > I pass a multidimensional array to a function, which is defined as
    > > int f(int a[10][10])

    >
    > Just to be clear, I assume you understand this actually declares a the
    > same type as int (*a) [10] . The C language allows you to pass e.g.


    Your assumption is correct.

    >
    > > {
    > > int *b=(void*)a;
    > > int *c=a[0];
    > > /*...*/
    > > }
    > > Now the questions come:
    > > - Is it guaranteed that b and c points to the same object (or is this
    > > implementation defined)?

    >
    > They're guaranteed to point to the same (one) int. It is theoretically
    > arguable how many of the following int's they can access; see below.
    >
    > > - Is it always true that a[1][1] refers to the same object as c[11] ?
    > > (There is no hole)

    >
    > It is guaranteed there is no hole between array elements, at any
    > level; thus a[0][0] is followed immediately by a[0][1], and a[0] as a
    > whole is followed immediately by a[1] as a whole, therefore a[0][9] is
    > followed immediately by a[1][0].


    Thanks, that's an important information. In covers that same statement
    that is actually being discussed in an other thread subjected as
    "Address of an array = address of its 1st".

    So I am happy to learn that there may no be an array overhead (data
    that belongs to the array and stored in the array before the first
    element)

    > And so it is guaranteed &a[0][10] == &a[1][0]. And, for example,
    > memcpy (tempi, (char*)a + 12*sizeof(int), sizeof(int))
    > will get you the value of a[1][2], and the reverse will set it.


    Good.

    > According to the strict abstract semantics, you can't dereference
    > &a[0][10] and can't form &a[0][11] or higher at all.


    I think this statement of yours is in contradiction with the previous
    one.
    &a[0][10] is equivalent to a[0]+10. For those who forgot: a[0] is
    an array of ten integers. That is why you say, *&a[0][10], or a[0][10]
    is not correct. But in fact, here this array (a[0]) decays to a
    pointer,
    so &a[0][10] is &a[0][0]+10. From this you claimed that it compares
    equal to &a[1][0], and if two pointers compare equal and are of the
    same type, and one of them points to an object within its lifetime,
    then
    the other pointer points to the same object, and hence, it can also be
    dereferenced.

    Szabolcs
     
    Szabolcs Borsanyi, May 23, 2008
    #4
  5. Re: Once again pointer to first element vs pointer to array castto pointer to element

    On Fri, May 23, 2008 at 12:14:42AM -0700, Szabolcs Borsanyi wrote:

    I've cut a discussion about a in the body of
    int f(int (*a)[10])

    > &a[0][10] is equivalent to a[0]+10. For those who forgot: a[0] is
    > an array of ten integers. That is why you say, *&a[0][10], or a[0][10]
    > is not correct. But in fact, here this array (a[0]) decays to a
    > pointer,
    > so &a[0][10] is &a[0][0]+10. From this you claimed that it compares
    > equal to &a[1][0], and if two pointers compare equal and are of the
    > same type, and one of them points to an object within its lifetime,
    > then
    > the other pointer points to the same object, and hence, it can also be
    > dereferenced.
    >
    > Szabolcs


    Here I have to correct myself.

    C99 6.5.9:

    6 Two pointers compare equal if and only if both are null pointers, both
    are pointers to the same object (including a pointer to an object and a
    subobject at its beginning) or function, both are pointers to one past the
    last element of the same array object, or one is a pointer to one past the
    end of one array object and the other is a pointer to the start of a
    different array object that happens to immediately follow the first array
    object in the address space.
    ------

    So if two pointers are equal, and one of the points to an object,
    they do not need to point to the same object.
    Strange isn't it...

    Szabolcs
     
    Szabolcs Borsanyi, May 23, 2008
    #5
  6. Re: Once again pointer to first element vs pointer to array cast to pointer to element

    Szabolcs Borsanyi <-heidelberg.de> writes:

    > On May 19, 4:59 am, David Thompson <> wrote:

    <snip>
    >> It is guaranteed there is no hole between array elements, at any
    >> level; thus a[0][0] is followed immediately by a[0][1], and a[0] as a
    >> whole is followed immediately by a[1] as a whole, therefore a[0][9] is
    >> followed immediately by a[1][0].

    >
    > Thanks, that's an important information. In covers that same statement
    > that is actually being discussed in an other thread subjected as
    > "Address of an array = address of its 1st".


    I think this is not quite the same thing. There two things involved:
    one is that there are no holes, the other is that a pointer to the
    whole object will compare equal (when suitably converted) to a pointer
    to an initial sub-object. There are specific and separate guarantees
    about both.

    > So I am happy to learn that there may no be an array overhead (data
    > that belongs to the array and stored in the array before the first
    > element)
    >
    >> And so it is guaranteed &a[0][10] == &a[1][0]. And, for example,
    >> memcpy (tempi, (char*)a + 12*sizeof(int), sizeof(int))
    >> will get you the value of a[1][2], and the reverse will set it.

    >
    > Good.
    >
    >> According to the strict abstract semantics, you can't dereference
    >> &a[0][10] and can't form &a[0][11] or higher at all.

    >
    > I think this statement of yours is in contradiction with the previous
    > one.


    No, there is no contradiction. The standard is worded to allow
    a pointer (at least in some cases) to know its bounds, i.e., the
    extent of the thing it points to. The conversion to, and access via,
    a char * is specifically guaranteed. De-referencing the pointer
    &a[0][10] and constructing &a[0][11] are not although, of course, the
    behaviour is undefined so it is perfectly OK for it to work (as it
    does on most implementations).

    > &a[0][10] is equivalent to a[0]+10. For those who forgot: a[0] is
    > an array of ten integers. That is why you say, *&a[0][10], or a[0][10]
    > is not correct. But in fact, here this array (a[0]) decays to a
    > pointer,
    > so &a[0][10] is &a[0][0]+10. From this you claimed that it compares
    > equal to &a[1][0], and if two pointers compare equal and are of the
    > same type, and one of them points to an object within its lifetime,
    > then
    > the other pointer points to the same object, and hence, it can also be
    > dereferenced.


    That is not guaranteed. &a[0][10] can be constructed because it is a
    "one past the end" pointer, but you can't de-reference it. Well, you
    probably can, but it is UB to do so. You have to image two pointers
    that compare equal because they discard the bounds information at that
    point, but one can't be de-referenced because the bounds kick in.

    --
    Ben.
     
    Ben Bacarisse, May 23, 2008
    #6
  7. Re: Once again pointer to first element vs pointer to array cast to pointer to element

    Szabolcs Borsanyi <> writes:

    <snip>
    > Here I have to correct myself.
    >
    > C99 6.5.9:
    >
    > 6 Two pointers compare equal if and only if both are null pointers, both
    > are pointers to the same object (including a pointer to an object and a
    > subobject at its beginning) or function, both are pointers to one past the
    > last element of the same array object, or one is a pointer to one past the
    > end of one array object and the other is a pointer to the start of a
    > different array object that happens to immediately follow the first array
    > object in the address space.
    > ------
    >
    > So if two pointers are equal, and one of the points to an object,
    > they do not need to point to the same object.
    > Strange isn't it...


    Yes. I think my previous reply may now be redundant. Sorry for the
    noise.

    --
    Ben.
     
    Ben Bacarisse, May 23, 2008
    #7
    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. Ante Perkovic

    Once again: validating the datagrid

    Ante Perkovic, Jun 25, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    898
    Ante Perkovic
    Jun 25, 2003
  2. =?Utf-8?B?TWF1cml6aW8gUG9sZXR0bw==?=

    Once logon, the web application returs to login page again

    =?Utf-8?B?TWF1cml6aW8gUG9sZXR0bw==?=, Mar 24, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    332
    Patrick.O.Ige
    Mar 25, 2006
  3. Spendius
    Replies:
    8
    Views:
    5,557
    Spendius
    Oct 22, 2003
  4. Hansen
    Replies:
    3
    Views:
    1,121
    rep_movsd
    Apr 24, 2010
  5. Gancy
    Replies:
    4
    Views:
    208
    Rasto Levrinc
    Feb 3, 2005
Loading...

Share This Page