shaunc@gold.gvg.tek.com (Shaun Case) (02/26/91)
I know that when you repeatedly access something like foo.a.b.c.d[11].value it is better to declare a (register) pointer, assign it the address of foo.a.b.c.d[11].value, and do manipulations on that, since it is faster. However, I am dealing with a heavily nested structure, such as: struct a { struct aa x; struct ab y; struct ac z; } le_struct; typedef struct aa { struct one something; struct two nothing; struct three everything; struct four whatever; }; typedef struct one { char foo; char foo2; short blah; short blah2; }; And... I want to access the various members of a.x.something (.foo, .foo2, .blah, .blah2) quickly. I have a function that I pass a pointer to type struct a, thus: void do_stuff (struct *a ptr) {} and what I want to do is something like register char *fastptr; fastptr = &(ptr->x.something) and then access fastptr->foo, fastptr->foo2, etc. I can't seem to get it to work. Is this possible? Help would be greatly appreciated, since the structure I am working with is 6 levels deep at some points, and I have to access every non-char element within it at least once. ( I think that from my foggy earlier days, what I am trying to do is equivalent to Pascal's WITH feature, in case what I was describing above isn't clear. It's been so long since I've used Pascal, tho, that I can no longer be sure. Thankfully. :-) ) // Shaun //
dave@cs.arizona.edu (Dave P. Schaumann) (02/26/91)
In article <1998@gold.gvg.tek.com> shaunc@gold.gvg.tek.com (Shaun Case) writes: >I know that when you repeatedly access something like > >foo.a.b.c.d[11].value > >it is better to declare a (register) pointer, assign it the address >of foo.a.b.c.d[11].value, and do manipulations on that, since it >is faster. Oh really? Seems to me that &foo.a.b.c.d[0] is a constant that can be computed *at compile time*. That means that (unless your comiler is totally brain-dead) accessing foo.a.b.c.d[0] should be as fast as accessing a normal element of an array of the same type. Yes, calculating the address does take a bit longer, but that calculation is done once by the compiler, and is known forever more. Now, if you had foo->a->b->c->d, you would certainly want to keep the address of d in a variable, rather than indirecting 4 times. -- Dave Schaumann | Is this question undecidable? dave@cs.arizona.edu |
torek@elf.ee.lbl.gov (Chris Torek) (02/26/91)
(This is a topic for comp.lang.c, not comp.std.c; I have redirected followups there.) In article <1998@gold.gvg.tek.com> shaunc@gold.gvg.tek.com (Shaun Case) writes: >I know that when you repeatedly access something like > >foo.a.b.c.d[11].value > >it is better to declare a (register) pointer, assign it the address >of foo.a.b.c.d[11].value, and do manipulations on that, since it >is faster. This is an unsupported assertion, and in fact it often turns out to be no faster (though usually no slower either). In particular, given ... >a heavily nested structure ... >I want to access the various members of a.x.something (.foo, .foo2, >.blah, .blah2) quickly. ... structures that are nested in this manner (where variable `a' is a structure containing a member `x' which itself is a structure containing a member `something' which itself is a structure containing members `foo', `foo2', etc.) are typically implemented such that computing &a.x.something.foo requires exactly as much work as computing &a.x or &a.x.something. For instance, on the 68010, the difference between: a.x.something.foo = 3; and: local_var = 3; is, in essence, moveq #3,a5@260 and moveq #3,a7@-32 both of which require exactly the same amount of time and space. On the other hand, writing ptr->x.something.foo = 3; ptr->x.something.foo2 = 3 * 3; ptr->x.something.blah = "headache"; is generally perceived to be less clear than writing: s->foo = 3; s->foo2 = 3 * 3; s->blah = "headache"; and if you agree, you should use the latter. >I have a function that I pass a pointer to type struct a, thus: > >void do_stuff (struct *a ptr) >{} > >and what I want to do is something like > >register char *fastptr; > >fastptr = &(ptr->x.something) > >and then access fastptr->foo, fastptr->foo2, etc. It would help greatly if your examples were legal C.... To take the conceptual error first: Declaring `fastptr' as `register char *fastptr' means that `fastptr' points to `char's. It does not point to structures. Since it does not point to structures, you may not use it to obtain elements of structures. If you want a pointer to point to one or more structures of type `struct glorp', you must declare it as a pointer to `struct glorp': struct glorp *g; Next, if `ptr' is to point to a `struct a', the proper syntax is: void do_stuff(struct a *ptr) Composing these and adding the assignment to make `g' point to the glorp member of the structure to which `ptr' points, we get: void do_stuff(struct a *ptr) { struct glorp *g; g = &ptr->x.something; At this point you can use `g->foo', `g->foo2', and so on exactly as above. It will likely be no faster (but more readable and/or less cumbersome) than using `ptr->x.something.foo', etc. On the other hand, if `ptr' were to point to a structure in which the sub-structures are not directly imbedded, but rather found through pointers, then: void do_stuff(struct object *o) { struct value *v; /* * Pick up object's current value pointer, * which is found by reading its attributes * to find its current binding, and then * reading the binding to find the current value. */ v = o->o_attr->a_binding->b_value; ... } in this case using `v' is more likely (but still not guaranteed!) to be faster than writing `o->o_attr->a_binding->b_value' each time. It is also almost certain to make those editing the code happier. -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab EE div (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov
volpe@camelback.crd.ge.com (Christopher R Volpe) (02/26/91)
In article <955@caslon.cs.arizona.edu>, dave@cs.arizona.edu (Dave P. Schaumann) writes: |>In article <1998@gold.gvg.tek.com> shaunc@gold.gvg.tek.com (Shaun Case) writes: |>>I know that when you repeatedly access something like |>> |>>foo.a.b.c.d[11].value |>> |>>it is better to declare a (register) pointer, assign it the address |>>of foo.a.b.c.d[11].value, and do manipulations on that, since it |>>is faster. |> |>Oh really? Seems to me that &foo.a.b.c.d[0] is a constant that can be |>computed *at compile time*. Oh really? What if the type of "foo.a.b.c.d" is "struct bar *" and you initialize it with: foo.a.b.c.d = (struct bar *) malloc(15 * sizeof(struct bar)); Then neither &foo.a.b.c.d[0] nor &foo.a.b.c.d[11] are compile time constants. ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
dave@cs.arizona.edu (Dave P. Schaumann) (02/27/91)
In article <17114@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes: |In article <955@caslon.cs.arizona.edu>, dave@cs.arizona.edu (Dave P. |Schaumann) writes: |||In article <1998@gold.gvg.tek.com> shaunc@gold.gvg.tek.com (Shaun |Case) writes: ||||I know that when you repeatedly access something like |||| ||||foo.a.b.c.d[11].value |||| ||||it is better to declare a (register) pointer, assign it the address ||||of foo.a.b.c.d[11].value, and do manipulations on that, since it ||||is faster. ||| |||Oh really? Seems to me that &foo.a.b.c.d[0] is a constant that can be |||computed *at compile time*. | |Oh really? What if the type of "foo.a.b.c.d" is "struct bar *" and you |initialize it with: | foo.a.b.c.d = (struct bar *) malloc(15 * sizeof(struct bar)); | |Then neither &foo.a.b.c.d[0] nor &foo.a.b.c.d[11] are compile time |constants. I think you're wrong. If the base address of foo is known at compile time, then &foo.a.b.c.d[0] is simply a constant offset from this base address, and this constant *must* calculatable at compile time for the compiler to generate code to access these fields. And even if the base address of foo is unknown at compile time, the expression foo.a.b.c.d still represents a known constant offset from an unknown base address. If you have foo.baz as the same type as foo.a.b.c.d, accessing foo.baz will take exactly the same amount of time *at run time* as foo.a.b.c.d, since they both represent a (different) fixed offset from the same base address. -- Dave Schaumann dave@cs.arizona.edu 'Dog Gang'! Where do they get off calling us the 'Dog Gang'? I'm beginning to think the party's over. I'm beginning to think maybe we don't need a dog. Or maybe we need a *new* dog. Or maybe we need a *cat*! - Amazing Stories
volpe@kirkwood.crd.ge.com (Christopher R Volpe) (02/28/91)
In article <964@caslon.cs.arizona.edu>, dave@cs.arizona.edu (Dave P. Schaumann) writes: |>In article <17114@crdgw1.crd.ge.com> volpe@camelback.crd.ge.com (Christopher R Volpe) writes: |>|In article <955@caslon.cs.arizona.edu>, dave@cs.arizona.edu (Dave P. |>|Schaumann) writes: |>|||Oh really? Seems to me that &foo.a.b.c.d[0] is a constant that can be |>|||computed *at compile time*. |>| |>|Oh really? What if the type of "foo.a.b.c.d" is "struct bar *" and you |>|initialize it with: |>| foo.a.b.c.d = (struct bar *) malloc(15 * sizeof(struct bar)); |>| |>|Then neither &foo.a.b.c.d[0] nor &foo.a.b.c.d[11] are compile time |>|constants. |> |>I think you're wrong. If the base address of foo is known at compile time, |>then &foo.a.b.c.d[0] is simply a constant offset from this base address, |>and this constant *must* calculatable at compile time for the compiler to |>generate code to access these fields. And even if the base address of foo is |>unknown at compile time, the expression foo.a.b.c.d still represents a known |>constant offset from an unknown base address. I don't think so. If the base address of {foo} is known at compile time, then the ADDRESS of {foo.a.b.c.d} is known at compile time. However, {&foo.a.b.c.d[0]} is by definition the VALUE of {foo.a.b.c.d}, which is the value returned by malloc, which is NOT known at compile time. Look again at what that expression is computing. It's the address of the first element of an array whose storage was allocated at run time. How can that be known at compile time? ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com