By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,473 Members | 3,598 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,473 IT Pros & Developers. It's quick & easy.

Using offsetof() values to access members of a struct

P: n/a
With offsetof() I can get the offset of a member in a struct. AFAICS,
it is portable and clean to use this offset to access that member. I
need to do something like this

struct foo {
struct foo *next;
int a;
int b;
int c;
};

void iterate(struct foo *list, size_t off)
{
struct foo *p;
for (p = list; p; p = p->next) {
int i = *(int *)((char *)p + off); /* [1] */
/* do something with i */
}
}

void func(struct foo *f)
{
iterate(f, offsetof(struct foo, a);
iterate(f, offsetof(struct foo, b);
iterate(f, offsetof(struct foo, c);
}

[1] Is this code portable and without undefined or implementation-defined
behavior?

Or is there a better way to achieve the same?

urs
May 22 '07 #1
Share this Question
Share on Google+
6 Replies


P: n/a
Urs Thuermann <ur*@isnogud.escape.dewrites:
With offsetof() I can get the offset of a member in a struct. AFAICS,
it is portable and clean to use this offset to access that member. I
need to do something like this

struct foo {
struct foo *next;
int a;
int b;
int c;
};

void iterate(struct foo *list, size_t off)
{
struct foo *p;
for (p = list; p; p = p->next) {
int i = *(int *)((char *)p + off); /* [1] */
/* do something with i */
}
}

void func(struct foo *f)
{
iterate(f, offsetof(struct foo, a);
iterate(f, offsetof(struct foo, b);
iterate(f, offsetof(struct foo, c);
}

[1] Is this code portable and without undefined or implementation-defined
behavior?
I think it is, but I am not one of the most skilled interpreters of
such matters. Stay tuned for more informed voices to come along.
Or is there a better way to achieve the same?
"Better" is a loaded word and the only information we have is that you
want portability. I would at least consider:

int access_a(struct foo *fp) { return fp->a; }
int access_b(struct foo *fp) { return fp->b; }
int access_c(struct foo *fp) { return fp->c; }

void iterate(struct foo *list, int (*access)(struct foo *))
{
struct foo *p;
for (p = list; p; p = p->next) {
int i = access(p);
/* do something with i... */
}
}

void func(struct foo *f)
{
iterate(f, access_a);
iterate(f, access_b);
iterate(f, access_c);
}

--
Ben.
May 22 '07 #2

P: n/a
Urs Thuermann wrote:
With offsetof() I can get the offset of a member in a struct. AFAICS,
it is portable and clean to use this offset to access that member. I
need to do something like this

struct foo {
struct foo *next;
int a;
int b;
int c;
};

void iterate(struct foo *list, size_t off)
{
struct foo *p;
for (p = list; p; p = p->next) {
int i = *(int *)((char *)p + off); /* [1] */
/* do something with i */
}
}

void func(struct foo *f)
{
iterate(f, offsetof(struct foo, a);
iterate(f, offsetof(struct foo, b);
iterate(f, offsetof(struct foo, c);
}

[1] Is this code portable and without undefined or implementation-defined
behavior?
The code at [1] is fine, but the calls to it have too few
parentheses.
Or is there a better way to achieve the same?
In this particular case, yes:

struct foo {
struct foo *next;
int abc[3];
};

.... and work with array indices instead of element offsets.

--
Eric Sosman
es*****@acm-dot-org.invalid
May 22 '07 #3

P: n/a
Urs Thuermann wrote:
With offsetof() I can get the offset of a member in a struct.
Yes.
AFAICS, it is portable
Yes.
and clean
That depends.
to use this offset to access that member. I
need to do something like this

struct foo {
struct foo *next;
int a;
int b;
int c;
};

void iterate(struct foo *list, size_t off)
{
struct foo *p;
for (p = list; p; p = p->next) {
int i = *(int *)((char *)p + off); /* [1] */
/* do something with i */
}
}

void func(struct foo *f)
{
iterate(f, offsetof(struct foo, a);
iterate(f, offsetof(struct foo, b);
iterate(f, offsetof(struct foo, c);
}

[1] Is this code portable and without undefined or implementation-defined
behavior?
Looks like it to me.
Or is there a better way to achieve the same?
Well, the natural and obvious solution is to use an array of
three elements and an index, rather than playing offset games.
That reduces the line

| int i = *(int *)((char *)p + off)

to
int i = p.arrayName[off];

which is, IMAO, twenty-seven times more comprehensible. (Obviously
you call `iterate` with values 0, 1, 2, rather than the offsetof
expressions.)

--
"There's a doorway where there was a wall" /Master Humpries Clock/

Hewlett-Packard Limited registered no:
registered office: Cain Road, Bracknell, Berks RG12 1HN 690597 England

May 22 '07 #4

P: n/a
Eric Sosman <es*****@acm-dot-org.invalidwrites:
The code at [1] is fine, but the calls to it have too few
parentheses.
Ah, yes. The whole example is not anywhere near to my real code, and
was only quickly hacked down for this posting. In my real code,
function names, struct names, and member names and types are
different. The real struct doesn't have three ints but a dozen
pointers to further linked lists which have to be traversed.

Currently, I have a separate iterate() function for each of the struct
members and all have exactly the same structure. I wanted to reduce
code duplication by somwehow passing an argument specifying which
member to work on.
Or is there a better way to achieve the same?

In this particular case, yes:

struct foo {
struct foo *next;
int abc[3];
};

... and work with array indices instead of element offsets.
Good idea. I'll probably convert my dozen of pointers to an array and
define symbolic names for the indices. Thanks for your suggestion.
urs
May 22 '07 #5

P: n/a
Others have answered the specific question; this is more general:

In article <yg*************@janus.isnogud.escape.de>,
Urs Thuermann <ur*@isnogud.escape.dewrote:
>With offsetof() I can get the offset of a member in a struct. AFAICS,
it is portable and clean to use this offset to access that member. ...
A structure member, inside a C compiler, really provides two items:
an offset, and a type. Given those two items -- offset and type --
you can "synthesize" a member-access.

The C syntax "structure.member" essentially means "using the
structure named on the left, which should be an lvalue[%], find
the address of the object implied by that lvalue, add the offset
implied by the member, and access an object whose type is
determined by the member." This rule also works for unions,
where the offset is always zero.

The "offset add" must be done in terms of "bytes" (C bytes, i.e.,
"unsigned char"s), of course. (&structure)+1, using ordinary
(i.e., entire-object-size) pointer arithmetic, points right
past the entire structure, so any nonzero offset would be too
big if this "offset add" were not "de-scaled" down to byte size.

-----
[%] This deliberately ignores the special case of a function return
value of structured type, which has some funny constraints. In
particular, such a return value is the only way to produce an
"array rvalue", which has no address, yet can still be subscripted
to access an array element. If you somehow access the (nonexistent)
address of a struct-type return value or any of its members --
including an array or an array element -- the effect is not defined.
It is generally unwise even to try, whether or not the compiler
catches you. :-)
-----

The C syntax "expr->member" essentially means "using the pointer
value given on the left, and the offset and type implied by
the member, access the object at that offset." This is of course
identical to "(*(expr)).member" since *(expr) produces the lvalue
pointed-to by the expression. Taking its address and adding the
offset has the same effect as just starting with the expression,
treating it as an address, and adding the offset.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
May 24 '07 #6

P: n/a
Chris Torek wrote:
[%] This deliberately ignores the special case of a function return
value of structured type, which has some funny constraints. In
particular, such a return value is the only way to produce an
"array rvalue", which has no address, yet can still be subscripted
to access an array element. If you somehow access the (nonexistent)
address of a struct-type return value or any of its members --
including an array or an array element -- the effect is not defined.
It is generally unwise even to try, whether or not the compiler
catches you. :-)
In C90, an array rvalue cannot be subscripted, and in C99, I don't believe
there is anything prohibiting

struct S { int a[1]; } s;
struct S f(void) { return s; }
int main(void) { int *p; return *(p = f().a); }

(though p may not be dereferenced after the next sequence point).

And function calls are not the only way. The conditional, assignment, and
comma operators can also do it.
May 25 '07 #7

This discussion thread is closed

Replies have been disabled for this discussion.