Velocity Reviews > Distance between struct members

# Distance between struct members

lovecreatesbea...@gmail.com
Guest
Posts: n/a

 10-18-2007
1. The following code snippet uses minus operation on two pointers to
calculate the distance between struct members. This is illegal, right?

2. s1 and s2 are type of the same struct S. Can the distance of s1.i4
between i3 be used to deduce the distance between s2.i4 and s2.i3?

#include <stdio.h>
#include <stddef.h>

struct S {
/*...*/
int i3;
/*...*/
int i4;
};

int main(void)
{
struct S s1, s2;
ptrdiff_t distance;

distance = &s1.i4 - &s1.i3;
s1.i3 = 11;
s1.i4 = 12;
s2.i3 = 13;
s2.i4 = 14;
printf("%d, %d\n", s2.i3, *(&s2.i3 + distance));
return 0;
}

Eric Sosman
Guest
Posts: n/a

 10-18-2007
(E-Mail Removed) wrote On 10/18/07 12:47,:
> 1. The following code snippet uses minus operation on two pointers to
> calculate the distance between struct members. This is illegal, right?

Yes. To see why (or one reason why, anyhow), remember
that pointer arithmetic operates in units of the pointed-to
type. Now consider what might lie in the /*...*/ between
members i3 and i4. If the size of what's there is not an
exact multiple of the size of an int, i3 and i4 are separated
by something-and-a-fraction units. Pointer arithmetic can't
handle the -and-a-fraction part.

> 2. s1 and s2 are type of the same struct S. Can the distance of s1.i4
> between i3 be used to deduce the distance between s2.i4 and s2.i3?

Yes, but let's tighten up what "distance" means. If
you express everything in units of bytes (rather than ints
or whatever), all will be well. C guarantees that

(char*)&s1.i4 - (char*)&s1.i3
== (char*)&s2.i4 - (char*)&s2.i3

However, there are no guarantees about

(char*)&s1.i3 - (char*)s2.i3

> Thank you for your time.
>
>
> #include <stdio.h>
> #include <stddef.h>
>
> struct S {
> /*...*/
> int i3;
> /*...*/
> int i4;
> };
>
> int main(void)
> {
> struct S s1, s2;
> ptrdiff_t distance;
>
> distance = &s1.i4 - &s1.i3;
> s1.i3 = 11;
> s1.i4 = 12;
> s2.i3 = 13;
> s2.i4 = 14;
> printf("%d, %d\n", s2.i3, *(&s2.i3 + distance));
> return 0;
> }
>

Keith Thompson
Guest
Posts: n/a

 10-18-2007
Eric Sosman <(E-Mail Removed)> writes:
> (E-Mail Removed) wrote On 10/18/07 12:47,:
>> 1. The following code snippet uses minus operation on two pointers to
>> calculate the distance between struct members. This is illegal, right?

>
> Yes. To see why (or one reason why, anyhow), remember
> that pointer arithmetic operates in units of the pointed-to
> type. Now consider what might lie in the /*...*/ between
> members i3 and i4. If the size of what's there is not an
> exact multiple of the size of an int, i3 and i4 are separated
> by something-and-a-fraction units. Pointer arithmetic can't
> handle the -and-a-fraction part.

[...]

Yes, but that's just one reason, and it depends on what you mean by
"illegal".

The real reason is that pointer subtraction invokes undefined behavior
if the two pointers point to distinct objects. See C99 6.5.6p9. This
applies even to subtraction of char* pointers, which are not affected
by alignment.

(In a typical implementation, the subtraction is likely to give you a
somewhat meaningful result. If the the difference is not a multiple
of the size of the pointed-to object, the remainder is likely to be
quitely ignored. But there are, of course, absolutely no guarantees.)

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Jack Klein
Guest
Posts: n/a

 10-19-2007
On Thu, 18 Oct 2007 15:21:21 -0700, Keith Thompson <(E-Mail Removed)>
wrote in comp.lang.c:

> Eric Sosman <(E-Mail Removed)> writes:
> > (E-Mail Removed) wrote On 10/18/07 12:47,:
> >> 1. The following code snippet uses minus operation on two pointers to
> >> calculate the distance between struct members. This is illegal, right?

> >
> > Yes. To see why (or one reason why, anyhow), remember
> > that pointer arithmetic operates in units of the pointed-to
> > type. Now consider what might lie in the /*...*/ between
> > members i3 and i4. If the size of what's there is not an
> > exact multiple of the size of an int, i3 and i4 are separated
> > by something-and-a-fraction units. Pointer arithmetic can't
> > handle the -and-a-fraction part.

> [...]
>
> Yes, but that's just one reason, and it depends on what you mean by
> "illegal".
>
> The real reason is that pointer subtraction invokes undefined behavior
> if the two pointers point to distinct objects. See C99 6.5.6p9. This
> applies even to subtraction of char* pointers, which are not affected
> by alignment.

I disagree about using pointer to char, specifically pointer to
unsigned.

Any object, including the structure in the OP's post, can be accessed
as a suitably sized array of unsigned char. It is legal, therefore,
to subtract the addresses of two members of the same structure,
provided of course they are cast to pointers to unsigned char.

The result will be a ptrdiff_t representing the number of bytes
between the first byte in the representation of the first member and
the first byte in the representation of the second member.

I do agree about using pointers to int, regardless of alignment
issues, because clearly two different int members of a structure are
not elements of the same array of ints.

> (In a typical implementation, the subtraction is likely to give you a
> somewhat meaningful result. If the the difference is not a multiple
> of the size of the pointed-to object, the remainder is likely to be
> quitely ignored. But there are, of course, absolutely no guarantees.)

Now the question is, can anybody find wording in the standard
(probably scattered abound in multiple places) that definitively makes
doing this with pointer to char or pointer to signed char well-defined
because it is well-defined for pointer to unsigned char?

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html

Keith Thompson
Guest
Posts: n/a

 10-19-2007
Jack Klein <(E-Mail Removed)> writes:
> On Thu, 18 Oct 2007 15:21:21 -0700, Keith Thompson <(E-Mail Removed)>
> wrote in comp.lang.c:
>> Eric Sosman <(E-Mail Removed)> writes:
>> > (E-Mail Removed) wrote On 10/18/07 12:47,:
>> >> 1. The following code snippet uses minus operation on two pointers to
>> >> calculate the distance between struct members. This is illegal, right?
>> >
>> > Yes. To see why (or one reason why, anyhow), remember
>> > that pointer arithmetic operates in units of the pointed-to
>> > type. Now consider what might lie in the /*...*/ between
>> > members i3 and i4. If the size of what's there is not an
>> > exact multiple of the size of an int, i3 and i4 are separated
>> > by something-and-a-fraction units. Pointer arithmetic can't
>> > handle the -and-a-fraction part.

>> [...]
>>
>> Yes, but that's just one reason, and it depends on what you mean by
>> "illegal".
>>
>> The real reason is that pointer subtraction invokes undefined behavior
>> if the two pointers point to distinct objects. See C99 6.5.6p9. This
>> applies even to subtraction of char* pointers, which are not affected
>> by alignment.

>
> I disagree about using pointer to char, specifically pointer to
> unsigned.
>
> Any object, including the structure in the OP's post, can be accessed
> as a suitably sized array of unsigned char. It is legal, therefore,
> to subtract the addresses of two members of the same structure,
> provided of course they are cast to pointers to unsigned char.

Certainly.

about subtracting pointers to members of distinct objects, rather than
pointers to members of the same object.

Subtracting two char* pointers, if they both point into the same
object (or just past its end) is valid. Subtracting two pointers of
any type that point to distinct objects invokes undefined behavior.
Subtracting two pointers to non-char types, both of which point into
the same structure, probably invokes undefined behavior because of the
alignment issues you mentioned above.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Eric Sosman
Guest
Posts: n/a

 10-19-2007
Keith Thompson wrote:
> Eric Sosman <(E-Mail Removed)> writes:
>> (E-Mail Removed) wrote On 10/18/07 12:47,:
>>> 1. The following code snippet uses minus operation on two pointers to
>>> calculate the distance between struct members. This is illegal, right?

>> Yes. To see why (or one reason why, anyhow), remember
>> that pointer arithmetic operates in units of the pointed-to
>> type. Now consider what might lie in the /*...*/ between
>> members i3 and i4. If the size of what's there is not an
>> exact multiple of the size of an int, i3 and i4 are separated
>> by something-and-a-fraction units. Pointer arithmetic can't
>> handle the -and-a-fraction part.

> [...]
>
> Yes, but that's just one reason, and it depends on what you mean by
> "illegal".
>
> The real reason is that pointer subtraction invokes undefined behavior
> if the two pointers point to distinct objects. See C99 6.5.6p9. This
> applies even to subtraction of char* pointers, which are not affected
> by alignment.

Well, that's no "reason" at all: It just states the Law
and offers no argument for why the Law should be as it is.
The most famous example of that particular argument is surely
"I am that I am," which few mortals can bring off believably.

In the example you snipped, the subtraction of int* pointers
was not well-defined but the subtraction of char* pointers was.

--
Eric Sosman
(E-Mail Removed)lid

Keith Thompson
Guest
Posts: n/a

 10-19-2007
Eric Sosman <(E-Mail Removed)> writes:
[...]
> In the example you snipped, the subtraction of int* pointers
> was not well-defined but the subtraction of char* pointers was.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Kenneth Brody
Guest
Posts: n/a

 10-19-2007
Keith Thompson wrote:
>
> Eric Sosman <(E-Mail Removed)> writes:
> > (E-Mail Removed) wrote On 10/18/07 12:47,:
> >> 1. The following code snippet uses minus operation on two pointers to
> >> calculate the distance between struct members. This is illegal, right?

> >
> > Yes. To see why (or one reason why, anyhow), remember
> > that pointer arithmetic operates in units of the pointed-to
> > type. Now consider what might lie in the /*...*/ between
> > members i3 and i4. If the size of what's there is not an
> > exact multiple of the size of an int, i3 and i4 are separated
> > by something-and-a-fraction units. Pointer arithmetic can't
> > handle the -and-a-fraction part.

> [...]
>
> Yes, but that's just one reason, and it depends on what you mean by
> "illegal".
>
> The real reason is that pointer subtraction invokes undefined behavior
> if the two pointers point to distinct objects. See C99 6.5.6p9. This
> applies even to subtraction of char* pointers, which are not affected
> by alignment.

But &s1.i4 and &s1.i3 are both pointers within s1, and therefore are
not "distinct objects". (I suppose the typical "IMO" disclaimer may
apply?)

Plus, as I understand it, it is perfectly legal to overlay an array
of unsigned chars on any object, and access any and all bytes within
that object through this array. How is casting &s1.i4 and &s1.i3 to
"unsigned char *" any different than overlaying an unsigned char
array?

On second thought, however, I can see that taking the addresses of
the two as their native "int *", you can say that the two ints are
not part of the same object, as they are not part of an array of
ints. (Which is why they may not be a multiple-of-sizeof-int bytes
apart.) It is the casting to "unsigned char *" which means that the
addresses can be treated "as-if" they were part of an array of
unsigned chars the size of the struct.

Perhaps we're both right?

> (In a typical implementation, the subtraction is likely to give you a
> somewhat meaningful result. If the the difference is not a multiple
> of the size of the pointed-to object, the remainder is likely to be
> quitely ignored. But there are, of course, absolutely no guarantees.)

I think offsetof() is the way to go here. The offset of s1.i3 is
guaranteed to be the same as the offset of s2.i3, assuming that s1
and s2 are the same type, and any arithmetic which arrives at that
offset is guaranteed to be properly aligned.

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <(E-Mail Removed)>

lovecreatesbea...@gmail.com
Guest
Posts: n/a

 10-19-2007
On Oct 19, 1:46 am, Eric Sosman <(E-Mail Removed)> wrote:
> (E-Mail Removed) wrote On 10/18/07 12:47,:
>
> > 1. The following code snippet uses minus operation on two pointers to
> > calculate the distance between struct members. This is illegal, right?

>
> Yes. To see why (or one reason why, anyhow), remember
> that pointer arithmetic operates in units of the pointed-to
> type. Now consider what might lie in the /*...*/ between
> members i3 and i4. If the size of what's there is not an
> exact multiple of the size of an int, i3 and i4 are separated
> by something-and-a-fraction units. Pointer arithmetic can't
> handle the -and-a-fraction part.
>
> > 2. s1 and s2 are type of the same struct S. Can the distance of s1.i4
> > between i3 be used to deduce the distance between s2.i4 and s2.i3?

>
> Yes, but let's tighten up what "distance" means. If
> you express everything in units of bytes (rather than ints
> or whatever), all will be well. C guarantees that
>
> (char*)&s1.i4 - (char*)&s1.i3
> == (char*)&s2.i4 - (char*)&s2.i3
>
> However, there are no guarantees about
>
> (char*)&s1.i3 - (char*)s2.i3
>

Thank you.

So, the extra casts make the code in the original post legal and
portable, doesn't it?

#include <stdio.h>
#include <stddef.h>

struct S {
/*...*/
int i3;
/*...*/
int i7;
};

int main(void)
{
struct S s1 = {11, 12}, s2 = {13, 14};
ptrdiff_t distance;

distance = (char *)&s1.i7 - (char *)&s1.i3;
printf("%d, %d\n", s2.i3, (int)*((char *)&s2.i3 + distance));
return 0;
}

> > Thank you for your time.

>
> > #include <stdio.h>
> > #include <stddef.h>

>
> > struct S {
> > /*...*/
> > int i3;
> > /*...*/
> > int i4;
> > };

>
> > int main(void)
> > {
> > struct S s1, s2;
> > ptrdiff_t distance;

>
> > distance = &s1.i4 - &s1.i3;
> > s1.i3 = 11;
> > s1.i4 = 12;
> > s2.i3 = 13;
> > s2.i4 = 14;
> > printf("%d, %d\n", s2.i3, *(&s2.i3 + distance));
> > return 0;
> > }- Hide quoted text -

>
> - Show quoted text -

lovecreatesbea...@gmail.com
Guest
Posts: n/a

 10-19-2007
On Oct 19, 10:28 pm, Kenneth Brody <(E-Mail Removed)> wrote:
> I think offsetof() is the way to go here. The offset of s1.i3 is
> guaranteed to be the same as the offset of s2.i3, assuming that s1
> and s2 are the same type, and any arithmetic which arrives at that
> offset is guaranteed to be properly aligned.

But the offsetof() uses size_t other than "char *" or "unsigned char
*" to designate the type of the addresses, why?

 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 OffTrackbacks are On Pingbacks are On Refbacks are Off Forum Rules

 Similar Threads Thread Thread Starter Forum Replies Last Post John Reye C Programming 28 05-08-2012 12:24 AM Alex Vinokur C++ 3 03-24-2011 04:33 PM JFCM Java 4 02-07-2006 11:32 AM Chris Fogelklou C Programming 36 04-20-2004 08:27 AM CoolPint C++ 8 12-14-2003 02:30 PM