473,387 Members | 1,698 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

find index, given pointer to member

ike
Could you please give your opinion on the portability of this code?

/* -------- begin findindex.c -------- */

struct Foo { int junk0; };
struct Bar { int junk1; struct Foo foo; int junk2; };

int findindex(struct Bar * bars, struct Foo * fooptr)
/* Pre:
* bars points to (the first element of) an array of Bar.
* fooptr points to the 'foo' member of an element of bars,
* i.e. fooptr == & bars[i].foo for some valid index i
* Returns:
* the actual value of i, as defined above.
*/
{
return ((char*)fooptr - (char*)&bars[0].foo) / sizeof *bars;
}

/* -------- end findindex.c -------- */

Ike
Nov 14 '05 #1
11 2801
ik*@iae.nl wrote:
Could you please give your opinion on the portability of this code? /* -------- begin findindex.c -------- */ struct Foo { int junk0; };
struct Bar { int junk1; struct Foo foo; int junk2; }; int findindex(struct Bar * bars, struct Foo * fooptr)
/* Pre:
* bars points to (the first element of) an array of Bar.
* fooptr points to the 'foo' member of an element of bars,
* i.e. fooptr == & bars[i].foo for some valid index i
* Returns:
* the actual value of i, as defined above.
*/
{
return ((char*)fooptr - (char*)&bars[0].foo) / sizeof *bars;
}


Looks ok to me (as long as the arguments are what you tell). An alter-
native would be

return (struct Bar*)((char*)fooptr - offset_of(struct Bar, foo)) - bars;

which avoids the (explicit) division. And did you think about returning
a size_t instead of an int (the result can't be negative or you called
it with invalid arguments)?
Regards, Jens
--
\ Jens Thoms Toerring ___ Je***********@physik.fu-berlin.de
\__________________________ http://www.toerring.de
Nov 14 '05 #2
ik*@iae.nl wrote:
Could you please give your opinion on the portability of this code? struct Foo { int junk0; };
struct Bar { int junk1; struct Foo foo; int junk2; };

int findindex(struct Bar * bars, struct Foo * fooptr)
/* Pre:
* bars points to (the first element of) an array of Bar.
* fooptr points to the 'foo' member of an element of bars,
* i.e. fooptr == & bars[i].foo for some valid index i
* Returns:
* the actual value of i, as defined above.
*/
{
return ((char*)fooptr - (char*)&bars[0].foo) / sizeof *bars;
}


Ow, that's convoluted. AFAICT, it's not strictly portable, but you'd be
hard put to find an implementation where it wouldn't work. It would
require willful perversity of the implementor.

Richard
Nov 14 '05 #3
In message <3a*************@uni-berlin.de>
Je***********@physik.fu-berlin.de wrote:
ik*@iae.nl wrote:
{
return ((char*)fooptr - (char*)&bars[0].foo) / sizeof *bars;
}


Looks ok to me (as long as the arguments are what you tell). An alter-
native would be

return (struct Bar*)((char*)fooptr - offset_of(struct Bar, foo)) - bars;

which avoids the (explicit) division.


It's worth noting that the implicit division by sizeof *bars in the latter
form is likely to be optimised better than the explicit one.

For an implicit division in a pointer subtraction, the compiler knows that
the result of the division must be exact, which allows a strength reduction
turning it into a simple modulo multiplication. Similar strength reductions
are possible for potentially non-exact divisions, but they are more
complicated.

--
Kevin Bracey, Principal Software Engineer
Tematic Ltd Tel: +44 (0) 1223 503464
182-190 Newmarket Road Fax: +44 (0) 1728 727430
Cambridge, CB5 8HE, United Kingdom WWW: http://www.tematic.com/
Nov 14 '05 #4
Richard Bos wrote:

ik*@iae.nl wrote:
Could you please give your opinion on the portability of this code?

struct Foo { int junk0; };
struct Bar { int junk1; struct Foo foo; int junk2; };

int findindex(struct Bar * bars, struct Foo * fooptr)
/* Pre:
* bars points to (the first element of) an array of Bar.
* fooptr points to the 'foo' member of an element of bars,
* i.e. fooptr == & bars[i].foo for some valid index i
* Returns:
* the actual value of i, as defined above.
*/
{
return ((char*)fooptr - (char*)&bars[0].foo) / sizeof *bars;
}


Ow, that's convoluted. AFAICT, it's not strictly portable,
but you'd be
hard put to find an implementation where it wouldn't work. It would
require willful perversity of the implementor.


Are you refering to the difference
exceding the range of ptrdiff_t?

--
pete
Nov 14 '05 #5
ike
Je***********@physik.fu-berlin.de wrote:
ik*@iae.nl wrote:
Could you please give your opinion on the portability of this code? struct Foo { int junk0; };
struct Bar { int junk1; struct Foo foo; int junk2; }; int findindex(struct Bar * bars, struct Foo * fooptr)
/* Pre:
* bars points to (the first element of) an array of Bar.
* fooptr points to the 'foo' member of an element of bars,
* i.e. fooptr == & bars[i].foo for some valid index i
* Returns:
* the actual value of i, as defined above.
*/
{
return ((char*)fooptr - (char*)&bars[0].foo) / sizeof *bars;
}
Looks ok to me (as long as the arguments are what you tell). An alter-
native would be return (struct Bar*)((char*)fooptr - offset_of(struct Bar, foo)) - bars;
In fact that was one of the solutions I made up myself earlier, but
some compilers bark at the cast from a pointer type with loose alignment
requirements (here: char *) to a pointer type with stricter alignment
requirements (here: struct Bar *), and I wanted the code to compile
cleanly on all platforms.

<nitpick> s/offset_of/offsetof/ </nitpick>
<nitpick> offsetof() needs stddef.h </nitpick>
which avoids the (explicit) division. And did you think about returning
a size_t instead of an int (the result can't be negative or you called
it with invalid arguments)?


Yes I did, but I wanted to keep the posted example as minimal as possible.
Using size_t would have required "#include <stddef.h>".
Nov 14 '05 #6
ik*@iae.nl wrote:

Je***********@physik.fu-berlin.de wrote:
did you think about returning a size_t

Yes I did,
but I wanted to keep the posted example as minimal as possible.
Using size_t would have required "#include <stddef.h>".


But with your explanation included,
it winds up being less than minimal.

And with this question:
"Could you please give your opinion on the portability of this code?"
you knew that the size_t issue was going to come up.

--
pete
Nov 14 '05 #7
ike
pete <pf*****@mindspring.com> wrote:
ik*@iae.nl wrote:

Je***********@physik.fu-berlin.de wrote:
> did you think about returning a size_t
Yes I did,
but I wanted to keep the posted example as minimal as possible.
Using size_t would have required "#include <stddef.h>".
But with your explanation included,
it winds up being less than minimal.
And with this question:
"Could you please give your opinion on the portability of this code?"
you knew that the size_t issue was going to come up.


The portability question was about the return expression,
apparently I should have stated that more clearly.
The rest of the code was only added to produce a small compilable example.

Kind regards,
Ike
Nov 14 '05 #8
ik*@iae.nl wrote:

pete <pf*****@mindspring.com> wrote:
ik*@iae.nl wrote:

Je***********@physik.fu-berlin.de wrote:
> did you think about returning a size_t Yes I did,
but I wanted to keep the posted example as minimal as possible.
Using size_t would have required "#include <stddef.h>".

But with your explanation included,
it winds up being less than minimal.
And with this question:
"Could you please give your opinion on
the portability of this code?"
you knew that the size_t issue was going to come up.


The portability question was about the return expression,
apparently I should have stated that more clearly.
The rest of the code was only added to produce
a small compilable example.


The return expression
((char*)fooptr - (char*)&bars[0].foo) / sizeof *bars
contains a subexpression
(char*)fooptr - (char*)&bars[0].foo
of type ptrdiff_t.

ptrdiff_t isn't guaranteed by the standard
to be big enough to be able to represent the difference
between two pointers.
In C89 there's not that much information available
to a program about the ptrdiff_t type.

My feeling from looking at the C89 and C99 standards, is that
the intention was for ptrdiff_t to either be larger than size_t
or at the very least, to be as big as the signed version of size_t,
but there's no guarantee like that in the standard.

Even if ptrdiff_t were always at least as
big as the signed version of size_t,
your ptrdiff_t expression is in a place where it might be required
to represent the whole range of size_t.

Here's what the standard says on the issue.
N869
6.5.6 Additive operators
[#9] When two pointers are subtracted, both shall point to
elements of the same array object, or one past the last
element of the array object; the result is the difference of
the subscripts of the two array elements. The size of the
result is implementation-defined, and its type (a signed
integer type) is ptrdiff_t defined in the <stddef.h> header.
If the result is not representable in an object of that
type, the behavior is undefined.

--
pete
Nov 14 '05 #9
pete <pf*****@mindspring.com> wrote:
Richard Bos wrote:

ik*@iae.nl wrote:
Could you please give your opinion on the portability of this code?

struct Foo { int junk0; };
struct Bar { int junk1; struct Foo foo; int junk2; };

int findindex(struct Bar * bars, struct Foo * fooptr)
/* Pre:
* bars points to (the first element of) an array of Bar.
* fooptr points to the 'foo' member of an element of bars,
* i.e. fooptr == & bars[i].foo for some valid index i
* Returns:
* the actual value of i, as defined above.
*/
{
return ((char*)fooptr - (char*)&bars[0].foo) / sizeof *bars;
}


Ow, that's convoluted. AFAICT, it's not strictly portable,
but you'd be
hard put to find an implementation where it wouldn't work. It would
require willful perversity of the implementor.


Are you refering to the difference exceding the range of ptrdiff_t?


No, I'm referring to the comparison of two pointers which do not point
to the same (struct Foo) object. AFAICT, it would be legal if the
pointers were struct Bar pointers, since then they'd be pointers to
members of an array. Now they're pointers to members of disjunct
objects. I would be very surprised at an implementation where this were
an actual problem, of course.

Richard
Nov 14 '05 #10
Richard Bos wrote:
pete <pf*****@mindspring.com> wrote:
Richard Bos wrote:
ik*@iae.nl wrote:

Could you please give your opinion on the portability of this
code?

struct Foo { int junk0; };
struct Bar { int junk1; struct Foo foo; int junk2; };

int findindex(struct Bar * bars, struct Foo * fooptr)
/* Pre:
* bars points to (the first element of) an array of Bar.
* fooptr points to the 'foo' member of an element of bars,
* i.e. fooptr == & bars[i].foo for some valid index i
* Returns:
* the actual value of i, as defined above.
*/
{
return ((char*)fooptr - (char*)&bars[0].foo) / sizeof *bars;
}

Ow, that's convoluted. AFAICT, it's not strictly portable, but
you'd be hard put to find an implementation where it wouldn't
work. It would require willful perversity of the implementor.


Are you refering to the difference exceding the range of ptrdiff_t?


No, I'm referring to the comparison of two pointers which do not
point to the same (struct Foo) object. AFAICT, it would be legal
if the pointers were struct Bar pointers, since then they'd be
pointers to members of an array. Now they're pointers to members
of disjunct objects. I would be very surprised at an
implementation where this were an actual problem, of course.


Can't you use offsetof(struct bar, foo) to convert the fooptr to a
barptr, and go on from there? You can certainly do the reverse, to
convert a barptr to a fooptr.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 14 '05 #11
CBFalconer <cb********@yahoo.com> wrote:
Richard Bos wrote:
No, I'm referring to the comparison of two pointers which do not
point to the same (struct Foo) object. AFAICT, it would be legal
if the pointers were struct Bar pointers, since then they'd be
pointers to members of an array. Now they're pointers to members
of disjunct objects. I would be very surprised at an
implementation where this were an actual problem, of course.


Can't you use offsetof(struct bar, foo) to convert the fooptr to a
barptr, and go on from there?


Yes, AFAICT. Which is one of the reasons why a normal implementation
would have to go out of its way to make the original fail.

Richard
Nov 14 '05 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

97
by: s | last post by:
Can I do this: #define MYSTRING "ABC" .. .. .. char mychar = MYSTRING; .. .. ..
2
by: Vince | last post by:
I have a very specific problem to solve but I cannot find a data structure for it. I don't know if I am posting on the good newsgroup but I cannot find a software.design group. I would like to...
4
by: Deniz Bahar | last post by:
Hello all, Often times programs in C have arrays used as buffers and shared among different sections of code. The need arises to have position indicators to point to different parts of an array...
2
by: Martin v. Löwis | last post by:
I've been working on PEP 353 for some time now. Please comment, in particular if you are using 64-bit systems. Regards, Martin PEP: 353 Title: Using ssize_t as the index type Version:...
13
by: Steve Edwards | last post by:
Hi, Given a map: typedef map<long, string, greater<long> > mapOfFreq; Is there a quicker way to find the rank (i.e. index) of the elememt that has the long value of x? At the moment I'm...
16
by: Petrakid | last post by:
Hey, I have a task to complete. I am trying to figure out the best way, in C++ to determine the following. There is this farm with pigs and chickens. Only the legs of the pigs and chickens look...
11
by: desktop | last post by:
How do I find the last element in the list numsx defined below? int* myfind(int* arr_start, int* arr_end, int& s) { int not_found = 666; int* result = &not_found; while (arr_start !=...
6
by: chris.kemmerer | last post by:
I am having a problem with templates and I hope someone here can help. I am writing a library that accepts data packets, parses them and saves the information for later use. One member of the...
2
by: everly | last post by:
Hi, I'm helping my friends band and making their MySpace. I messed something up and I can't figure out what it is. Everything is all out of whack on the bottom half of the page. The comments...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.