Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Pointer to inside an array

Reply
Thread Tools

Pointer to inside an array

 
 
Barry Schwarz
Guest
Posts: n/a
 
      12-17-2009
On Wed, 16 Dec 2009 17:50:42 +0000 (UTC), Alok Singhal
<(E-Mail Removed)> wrote:

>On Tue, 15 Dec 2009 18:31:44 -0800, Barry Schwarz wrote:
>> On Tue, 15 Dec 2009 20:06:07 +0000 (UTC), Alok Singhal
>> <(E-Mail Removed)> wrote:
>>>>
>>>> int a[20] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,2 0};
>>>>
>>>> int (*p)[5] = (int(*)[5])(a+6);

>>
>> Think again. The purpose of the cast is not to silence the warning but
>> to coerce the value of the expression to a compatible type and eliminate
>> the condition that requires a diagnostic.
>>
>> The code
>> unsigned char *ptr = (unsigned char*)(a+6);
>> will produce the exact same warning without the cast yet the
>> initialization is perfectly well defined as written.

>
>Thanks. This is what I was looking for. I should have read the standard
>more carefully as well. So 6.3.2.3p7 (N1336) applies here:
>
> A pointer to an object or incomplete type may be converted to a
> pointer to a different object or incomplete type. If the resulting
> pointer is not correctly aligned for the pointed-to type, the behavior
> is undefined. Otherwise, when converted back again, the result shall
> compare equal to the original pointer.
>
>There is no guarantee that int (*)[5] is correctly aligned for int *, and
>even if it is, the standard makes no guarantees about dereferencing such
>a pointer.


Do you just invent these assumptions or do you read them somewhere
that we can tell others to avoid?

int array[5] = {2};
int (*ptr_a)[5] = &array;
int *ptr_i = array;

Is there any doubt in your mind that both pointers point to the same
address in memory? Is there any doubt that the expression
(unsigned char*)ptr_a == (unsigned char*)ptr_i
will evaluate to 1.

Is there any doubt in your mind that ptr_i[0] references the first
element of the array and evaluates to 2 while ptr_i[1] references the
second element and evaluates to 0?

Is there any doubt in your mind ptr_a[0][0] and ptr_a[0][1] reference
the exact same objects and hence must evaluate to the same values?

--
Remove del for email
 
Reply With Quote
 
 
 
 
Barry Schwarz
Guest
Posts: n/a
 
      12-17-2009
On Wed, 16 Dec 2009 09:27:28 -0800 (PST), annalissa
<(E-Mail Removed)> wrote:

>On Dec 15, 11:00*pm, Peter Nilsson <(E-Mail Removed)> wrote:
>> annalissa <(E-Mail Removed)> wrote:
>> > mohangupta13 <(E-Mail Removed)> wrote:
>> > > Alok *Singhal <(E-Mail Removed)> wrote:> Hi,
>> > > > Let's say I have:

>>
>> > > > int a[20] = {0};

>>
>> > > > Is the declaration below legal according to C89?

>>
>> > > > int (*p)[5] = (int (*)[5])(a+6);

>>
>> Depends on wheather a+6 is properly aligned for an int(*)[5].
>> If not, then no, it's not valid. I don't believe the standard
>> guarantees you can dereference it, only convert it back to an
>> int *. Also, you are accessing part of an object using a
>> different type to the effective type.
>>
>>
>>
>> > consider this program:-

>> <snip>
>>
>> > compile this program as gcc -g -ansi -pedantic -o progname
>> > progname.c , then decide for yourself

>>
>> That something compiles without a diagnostic under gcc does not
>> mean it is correct. E.g. ...
>>
>> * int main(void) { return * (int *) 0; }

>
>
>what is the diagnostic that i am missing ..??


There is no diagnostic required but the code invokes undefined
behavior.

--
Remove del for email
 
Reply With Quote
 
 
 
 
Alok Singhal
Guest
Posts: n/a
 
      12-17-2009
On Wed, 16 Dec 2009 21:47:47 -0800, Barry Schwarz wrote:
> On Wed, 16 Dec 2009 17:50:42 +0000 (UTC), Alok Singhal
> <(E-Mail Removed)> wrote:


<snip>

>>Thanks. This is what I was looking for. I should have read the
>>standard more carefully as well. So 6.3.2.3p7 (N1336) applies here:
>>
>> A pointer to an object or incomplete type may be converted to a
>> pointer to a different object or incomplete type. If the resulting
>> pointer is not correctly aligned for the pointed-to type, the behavior
>> is undefined. Otherwise, when converted back again, the result shall
>> compare equal to the original pointer.
>>
>>There is no guarantee that int (*)[5] is correctly aligned for int *,
>>and even if it is, the standard makes no guarantees about dereferencing
>>such a pointer.

>
> Do you just invent these assumptions or do you read them somewhere that
> we can tell others to avoid?


Please bear with me while I try to explain myself. Isn't there a
difference between:

int array[5] = {2};
int (*ptr)[5] = &array;

and:

int array[20] = {2};
int (*ptr)[5] = (int (*)[5])(array + 6);

In the second snippet, "array + 6" is of type "pointer to int". In the
first snippet, "&array" is of type "int (*)[5]". So, if I understand
correctly, and I think that is what you're saying too: the first snippet
is well-defined by the standard, while the result second snippet, in
particular the assignment to "ptr" is implementation-defined.

So, *if I understand correctly*, in the second snippet above:

- the cast is needed because it coerces "a+6" to the correct type for
"ptr".
- if "ptr" is a pointer to (signed or unsigned) char, or any other type
that is correctly aligned for the type of "a+6" (int *), the
initialization is well-defined in that I can convert "ptr" back to
int * and get the same value.
- if "ptr" isn't correctly aligned for int *, the result of the
initialization is implementation-defined.

Please let me know where I am wrong in my assumptions.

> int array[5] = {2};
> int (*ptr_a)[5] = &array;
> int *ptr_i = array;
>
> Is there any doubt in your mind that both pointers point to the same
> address in memory? Is there any doubt that the expression
> (unsigned char*)ptr_a == (unsigned char*)ptr_i
> will evaluate to 1.
>
> Is there any doubt in your mind that ptr_i[0] references the first
> element of the array and evaluates to 2 while ptr_i[1] references the
> second element and evaluates to 0?
>
> Is there any doubt in your mind ptr_a[0][0] and ptr_a[0][1] reference
> the exact same objects and hence must evaluate to the same values?


The answer to all the above questions is, "no". I agree with all the
statements above.

Thanks again for your help,
-Alok
 
Reply With Quote
 
Barry Schwarz
Guest
Posts: n/a
 
      12-18-2009
On Thu, 17 Dec 2009 17:54:54 +0000 (UTC), Alok Singhal
<(E-Mail Removed)> wrote:

>On Wed, 16 Dec 2009 21:47:47 -0800, Barry Schwarz wrote:
>> On Wed, 16 Dec 2009 17:50:42 +0000 (UTC), Alok Singhal
>> <(E-Mail Removed)> wrote:

>
><snip>
>
>>>Thanks. This is what I was looking for. I should have read the
>>>standard more carefully as well. So 6.3.2.3p7 (N1336) applies here:
>>>
>>> A pointer to an object or incomplete type may be converted to a
>>> pointer to a different object or incomplete type. If the resulting
>>> pointer is not correctly aligned for the pointed-to type, the behavior
>>> is undefined. Otherwise, when converted back again, the result shall
>>> compare equal to the original pointer.
>>>
>>>There is no guarantee that int (*)[5] is correctly aligned for int *,
>>>and even if it is, the standard makes no guarantees about dereferencing
>>>such a pointer.

>>
>> Do you just invent these assumptions or do you read them somewhere that
>> we can tell others to avoid?

>
>Please bear with me while I try to explain myself. Isn't there a
>difference between:
>
> int array[5] = {2};
> int (*ptr)[5] = &array;
>
>and:
>
> int array[20] = {2};
> int (*ptr)[5] = (int (*)[5])(array + 6);
>
>In the second snippet, "array + 6" is of type "pointer to int". In the
>first snippet, "&array" is of type "int (*)[5]". So, if I understand
>correctly, and I think that is what you're saying too: the first snippet
>is well-defined by the standard, while the result second snippet, in
>particular the assignment to "ptr" is implementation-defined.
>
>So, *if I understand correctly*, in the second snippet above:
>
>- the cast is needed because it coerces "a+6" to the correct type for
> "ptr".
>- if "ptr" is a pointer to (signed or unsigned) char, or any other type
> that is correctly aligned for the type of "a+6" (int *), the
> initialization is well-defined in that I can convert "ptr" back to
> int * and get the same value.
>- if "ptr" isn't correctly aligned for int *, the result of the
> initialization is implementation-defined.


If the value a+6 is correctly aligned for the type int(*)[5], then
your initialization of ptr is well defined. If not, the
initialization invokes undefined behavior (6.3.2.3-7), not
implementation defined behavior. So the question revolves around
whether a+6 is properly aligned.

Consider the definition
int x[sizeof(int)][5];

We know that each element x[i][j] occupies exactly sizeof(int) bytes.
Further more, each element x[i][j+1] starts exactly sizeof(int) bytes
beyond the start of the previous element x[i][j] (except for the
obvious boundary condition when j==4).

We also know that each x[i] is an array of 5 int and that x[i+1]
starts exactly 5*sizeof(int) bytes beyond the start of x[i] (again
except for the boundary condition when i==sizeof(int)-1).

Because sizeof(int) is not a factor of 5, I assert the x[i] as a group
completely exhaust all possible alignments for int[5] and that they
also completely exhaust all possible alignments for int. (I don't
remember what the branch of mathematics is called that is used to
prove these assertions but if you choose both common (2, 4, and and
off-the-wall (3, 15 23) values for sizeof(int) and work out the
addresses you should be convinced.) Consequently, the value a+6 will
exactly match the alignment of at least one of the x[i] and is
therefore properly aligned.

>
>Please let me know where I am wrong in my assumptions.
>


--
Remove del for email
 
Reply With Quote
 
Peter Nilsson
Guest
Posts: n/a
 
      12-18-2009
Barry Schwarz <(E-Mail Removed)> wrote:
> Alok Singhal
> > Please bear with me while I try to explain myself. Isn't
> > there a difference between:
> >
> > int array[5] = {2};
> > int (*ptr)[5] = &array;
> >
> > and:
> >
> > int array[20] = {2};
> > int (*ptr)[5] = (int (*)[5])(array + 6);

>
> ...the question revolves around whether a+6 is properly aligned.
>
> Consider the definition
> int x[sizeof(int)][5];


I have no idea why you think sizeof(int) should be used here!

> We know that each element x[i][j] occupies exactly sizeof(int)
> bytes. Further more, each element x[i][j+1] starts exactly
> sizeof(int) bytes beyond the start of the previous element
> x[i][j] (except for the obvious boundary condition when j==4).
>
> We also know that each x[i] is an array of 5 int and that
> x[i+1] starts exactly 5*sizeof(int) bytes beyond the start
> of x[i] (again except for the boundary condition when i==
> sizeof(int)-1).
>
> Because sizeof(int) is not a factor of 5,


Not commonly, but on the virtual machine it may be.

> I assert the x[i] as a group completely exhaust all possible
> alignments for int[5] and that they also completely exhaust
> all possible alignments for int. ...


I've had a previous discussion considering something like...

int a[7];
int (*p)[2] = (int (*)[2]) (a + 1);

The problem is whether int(*)[2] can have a stricter
alignement than int *. I think it can! I can't see anything
in the standard that says a pointer to an element of an array
of N elements will always be properly aligned for a pointer
to an array of M elements if M < N.

Why should it? Look at an example using structs...

struct int_pair_t { int a; int b; };
int a[7];
struct int_pair_t *p = (struct int_pair_t *) (a + 1);

Even if one shows that there is no padding in the struct,
there is still no guarantee that a + 1 is properly aligned
for a struct int_pair_t *.

Simple question: Is there anything precluding an
implementation giving struct int_pair_t a stricter
alignment than int?

[This is ignoring the issue of effective type which plays
a further role in the discussion.]

--
Peter
 
Reply With Quote
 
Barry Schwarz
Guest
Posts: n/a
 
      12-19-2009
On Thu, 17 Dec 2009 19:45:28 -0800 (PST), Peter Nilsson
<(E-Mail Removed)> wrote:

>Barry Schwarz <(E-Mail Removed)> wrote:
>> Alok Singhal
>> > Please bear with me while I try to explain myself. Isn't
>> > there a difference between:
>> >
>> > int array[5] = {2};
>> > int (*ptr)[5] = &array;
>> >
>> > and:
>> >
>> > int array[20] = {2};
>> > int (*ptr)[5] = (int (*)[5])(array + 6);

>>
>> ...the question revolves around whether a+6 is properly aligned.
>>
>> Consider the definition
>> int x[sizeof(int)][5];

>
>I have no idea why you think sizeof(int) should be used here!


I thought it would insure exhaustion but, as you point out below, it
works only for currently common implementations and fails in the
perverse case.

>
>> We know that each element x[i][j] occupies exactly sizeof(int)
>> bytes. Further more, each element x[i][j+1] starts exactly
>> sizeof(int) bytes beyond the start of the previous element
>> x[i][j] (except for the obvious boundary condition when j==4).
>>
>> We also know that each x[i] is an array of 5 int and that
>> x[i+1] starts exactly 5*sizeof(int) bytes beyond the start
>> of x[i] (again except for the boundary condition when i==
>> sizeof(int)-1).
>>
>> Because sizeof(int) is not a factor of 5,

>
>Not commonly, but on the virtual machine it may be.
>
>> I assert the x[i] as a group completely exhaust all possible
>> alignments for int[5] and that they also completely exhaust
>> all possible alignments for int. ...

>
>I've had a previous discussion considering something like...
>
> int a[7];
> int (*p)[2] = (int (*)[2]) (a + 1);
>
>The problem is whether int(*)[2] can have a stricter
>alignement than int *. I think it can! I can't see anything
>in the standard that says a pointer to an element of an array
>of N elements will always be properly aligned for a pointer
>to an array of M elements if M < N.


Yes. If the dimension of the array pointed to is a factor of
sizeof(int), then my argument fails. For example, if sizeof(int) is 4
and the alignment for int[2] is 8, then obviously a+1 or a+2 must be
misaligned for p.

Applying this to the specific example under consideration where the
dimension is 5, this can happen only if the alignment for an int[5] is
a multiple of 5*sizeof(int), such as 20 to match the example. In such
a case, array+6 may or may not be properly aligned but if it is then
array+7 is definitely not.

So to the OP I apologize for the error in my response. It is probably
properly aligned on all current systems you are likely to run on but
it may very well invoke undefined behavior on the DS9K or some new
system where the alignment of int[5] is more restrictive than that of
int.

>
>Why should it? Look at an example using structs...
>
> struct int_pair_t { int a; int b; };
> int a[7];
> struct int_pair_t *p = (struct int_pair_t *) (a + 1);
>
>Even if one shows that there is no padding in the struct,
>there is still no guarantee that a + 1 is properly aligned
>for a struct int_pair_t *.
>
>Simple question: Is there anything precluding an
>implementation giving struct int_pair_t a stricter
>alignment than int?
>
>[This is ignoring the issue of effective type which plays
>a further role in the discussion.]


--
Remove del for email
 
Reply With Quote
 
Alok Singhal
Guest
Posts: n/a
 
      12-19-2009
On Dec 17, 7:02*pm, Barry Schwarz <(E-Mail Removed)> wrote:
>
> So the question revolves around whether a+6 is properly aligned.


Yes, I think I wasn't clear enough in my posts so far. This indeed
was my question to begin with.

> Consider the definition
> * *int x[sizeof(int)][5];
>
> We know that each element x[i][j] occupies exactly sizeof(int) bytes.
> Further more, each element x[i][j+1] starts exactly sizeof(int) bytes
> beyond the start of the previous element x[i][j] (except for the
> obvious boundary condition when j==4).
>
> We also know that each x[i] is an array of 5 int and that x[i+1]
> starts exactly 5*sizeof(int) bytes beyond the start of x[i] (again
> except for the boundary condition when i==sizeof(int)-1).
>
> Because sizeof(int) is not a factor of 5, I assert the x[i] as a group
> completely exhaust all possible alignments for int[5] and that they
> also completely exhaust all possible alignments for int. *(I don't
> remember what the branch of mathematics is called that is used to
> prove these assertions but if you choose both common (2, 4, and and
> off-the-wall (3, 15 23) values for sizeof(int) and work out the
> addresses you should be convinced.) *Consequently, the value a+6 will
> exactly match the alignment of at least one of the x[i] and is
> therefore properly aligned.


OK. I see. I can agree with your arguments. But sizeof(int) can be a
factor of 5 theoretically, and the number 5 in my original post is
something I picked out of convenience. In general, it could be any
number (2, 8, 4, whatever). Similarly, the same goes for the numbers
and 6, and 20 in my original post. So, given

int a[N] = {0};
int (*p)[m] = (int (*)[m])(a+k);

with N, m, k as integers (and k+m < N of course), I can't be sure if a
+k is properly aligned for int (*)[m]?

Thanks a lot for your responses!

-Alok
 
Reply With Quote
 
Alok Singhal
Guest
Posts: n/a
 
      12-19-2009
On Dec 19, 12:58*am, Barry Schwarz <(E-Mail Removed)> wrote:
> On Thu, 17 Dec 2009 19:45:28 -0800 (PST), Peter Nilsson
>
> So to the OP I apologize for the error in my response. *It is probably
> properly aligned on all current systems you are likely to run on but
> it may very well invoke undefined behavior on the DS9K or some new
> system where the alignment of int[5] is more restrictive than that of
> int.


No need for the apology - I learned quite a lot from your and Peter's
answers, and I should have been more specific to begin with. After
all these years of lurking here in clc, I thought I was ready to post
an interesting question (interesting to me anyway).

-Alok
 
Reply With Quote
 
Seebs
Guest
Posts: n/a
 
      12-19-2009
On 2009-12-18, Peter Nilsson <(E-Mail Removed)> wrote:
> The problem is whether int(*)[2] can have a stricter
> alignement than int *. I think it can! I can't see anything
> in the standard that says a pointer to an element of an array
> of N elements will always be properly aligned for a pointer
> to an array of M elements if M < N.


I am pretty sure arrays don't actually have alignment requirements,
only the objects in them.

> Why should it? Look at an example using structs...
>
> struct int_pair_t { int a; int b; };
> int a[7];
> struct int_pair_t *p = (struct int_pair_t *) (a + 1);
>
> Even if one shows that there is no padding in the struct,
> there is still no guarantee that a + 1 is properly aligned
> for a struct int_pair_t *.


For a struct, this might be true. For an array, it's not.

> Simple question: Is there anything precluding an
> implementation giving struct int_pair_t a stricter
> alignment than int?


I'm not sure. I think in practice you probably can't, because you can
set up an elaborate construct involving unions which allows you to prove
that you have to be able to treat a pointer to a large enough hunk of
space which is aligned properly for an int as a pointer to the first member
of the structure.

But structs are not the same thing as arrays. I am pretty sure that
array-of-foo has to have the same alignment requirements as foo, because
any foo can be treated as an array of 1 foo, and you can treat any pointer
to foo as an array of foo. Basically, the wording guaranteeing that
the offset in bytes of foo[1] is precisely sizeof(foo[0]) covers it.

So I'm pretty sure that arrays can't have alignment requirements more
restrictive than the alignment requirements of the things they're arrays
of.

-s
--
Copyright 2009, all wrongs reversed. Peter Seebach / http://www.velocityreviews.com/forums/(E-Mail Removed)
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      12-19-2009
Seebs <(E-Mail Removed)> writes:
> On 2009-12-18, Peter Nilsson <(E-Mail Removed)> wrote:
>> The problem is whether int(*)[2] can have a stricter
>> alignement than int *. I think it can! I can't see anything
>> in the standard that says a pointer to an element of an array
>> of N elements will always be properly aligned for a pointer
>> to an array of M elements if M < N.

>
> I am pretty sure arrays don't actually have alignment requirements,
> only the objects in them.
>
>> Why should it? Look at an example using structs...
>>
>> struct int_pair_t { int a; int b; };
>> int a[7];
>> struct int_pair_t *p = (struct int_pair_t *) (a + 1);
>>
>> Even if one shows that there is no padding in the struct,
>> there is still no guarantee that a + 1 is properly aligned
>> for a struct int_pair_t *.

>
> For a struct, this might be true. For an array, it's not.


I'd like to think that's true, but I'm not entirely convinced unless
it can be proven from the standard.

>> Simple question: Is there anything precluding an
>> implementation giving struct int_pair_t a stricter
>> alignment than int?

>
> I'm not sure. I think in practice you probably can't, because you can
> set up an elaborate construct involving unions which allows you to prove
> that you have to be able to treat a pointer to a large enough hunk of
> space which is aligned properly for an int as a pointer to the first member
> of the structure.
>
> But structs are not the same thing as arrays. I am pretty sure that
> array-of-foo has to have the same alignment requirements as foo, because
> any foo can be treated as an array of 1 foo, and you can treat any pointer
> to foo as an array of foo. Basically, the wording guaranteeing that
> the offset in bytes of foo[1] is precisely sizeof(foo[0]) covers it.


Yes, but it doesn't follow from that that an array type can't have
a stricter alignment requirement than its element type.

> So I'm pretty sure that arrays can't have alignment requirements more
> restrictive than the alignment requirements of the things they're arrays
> of.


Consider a hypothetical implementation in which int is 4 bytes (32
bits), and the CPU has instructions that can access 4-byte and 8-byte
objects in memory, but only if they're 4-byte or 8-byte aligned.
The implementation imposes a 4-byte alignment requirement on int
objects. It also imposes an 8-byte alignment on int[N] objects,
where N is even. (The question is whether the latter requirement
is allowed.)

I declare an arr of int:

int arr2[4];

Each element is 4-byte aligned. The object as a whole is 8-byte
aligned.

For most operations, everything works just as you'd expect. The
question is whether this:

typedef int pair[2];
pair *p = (pair*)&arr2[1];

is valid, or whether operations on p can invoke undefined behavior
because of the alignment mismatch.

If an implementation causes the initialization of p to trap, for
example, what clause of the standard does the implementation violate?

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

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
pointer to an array vs pointer to pointer subramanian100in@yahoo.com, India C Programming 5 09-23-2011 10:28 AM
Cast a pointer to array to base class pointer to array Hansen C++ 3 04-24-2010 03:30 PM
Pointer to array of array of const pointer RSL C++ 14 02-19-2010 02:06 PM
Array of pointer and pointer of array erfan C Programming 6 01-28-2008 08:55 PM
Array of pointer Vs Pointer to Array sangeetha C Programming 9 10-09-2004 07:01 PM



Advertisments