Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   Distance between struct members (http://www.velocityreviews.com/forums/t545270-distance-between-struct-members.html)

 lovecreatesbea...@gmail.com 10-18-2007 04:47 PM

Distance between struct members

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 10-18-2007 05:46 PM

Re: Distance between struct members

lovecreatesbea...@gmail.com 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 10-18-2007 10:21 PM

Re: Distance between struct members

Eric Sosman <Eric.Sosman@sun.com> writes:
> lovecreatesbea...@gmail.com 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) kst-u@mib.org <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 10-19-2007 02:16 AM

Re: Distance between struct members

On Thu, 18 Oct 2007 15:21:21 -0700, Keith Thompson <kst-u@mib.org>
wrote in comp.lang.c:

> Eric Sosman <Eric.Sosman@sun.com> writes:
> > lovecreatesbea...@gmail.com 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 10-19-2007 02:42 AM

Re: Distance between struct members

Jack Klein <jackklein@spamcop.net> writes:
> On Thu, 18 Oct 2007 15:21:21 -0700, Keith Thompson <kst-u@mib.org>
> wrote in comp.lang.c:
>> Eric Sosman <Eric.Sosman@sun.com> writes:
>> > lovecreatesbea...@gmail.com 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) kst-u@mib.org <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 10-19-2007 02:46 AM

Re: Distance between struct members

Keith Thompson wrote:
> Eric Sosman <Eric.Sosman@sun.com> writes:
>> lovecreatesbea...@gmail.com 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
esosman@ieee-dot-org.invalid

 Keith Thompson 10-19-2007 05:38 AM

Re: Distance between struct members

Eric Sosman <esosman@ieee-dot-org.invalid> 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) kst-u@mib.org <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 10-19-2007 02:28 PM

Re: Distance between struct members

Keith Thompson wrote:
>
> Eric Sosman <Eric.Sosman@sun.com> writes:
> > lovecreatesbea...@gmail.com 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: <mailto:ThisIsASpamTrap@gmail.com>

 lovecreatesbea...@gmail.com 10-19-2007 06:43 PM

Re: Distance between struct members

On Oct 19, 1:46 am, Eric Sosman <Eric.Sos...@sun.com> wrote:
> lovecreatesbea...@gmail.com 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 10-19-2007 06:46 PM

Re: Distance between struct members

On Oct 19, 10:28 pm, Kenneth Brody <kenbr...@spamcop.net> 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?

All times are GMT. The time now is 03:37 AM.