Deep question for the REAL C GURU's out there ...

Kurt Wall kwall
Wed Feb 23 21:08:43 PST 2005


On Wednesday 23 February 2005 11:11, Ben Duncan enlightened us thusly:
> Ok, have been slag'ing away ( ;-> ) on my project.
> Done a LOT of reading of other's C projects and AM always getting
> tripped up by there usage of  structptr1->structptr2->myitem.
>
> Now, IS this not where a structure contains another structure and the
> above is pointing to the sub-structure inside the main structure?

myitem is an element of the structure pointed to by structptr2; 
structptr2 is an element of the structure to which structptr1 points.

>
> Now given that this is how I see everone else doing things and given
> the below code: (see rest of email following code)
>
> ---------------------------------------------------------------------
>---------- /* C code snippet */
>
> typedef struct Menu_Set Menu ;
> typedef struct menu_line_item menulineitem ;
> typedef struct Menu_Status menustat ;
>
> struct Menu_Status
> {
>      int ms_counter ;
>      int ms_users ;
>      char ms_status ;
>      char ms_message [ 80 ] ;
> }
>
> struct menu_line_item
> {
>      int  mli_lineid ;
>      char mli_displayname [ 16 ] ;
>      char mli_type [ 8 ] ;
>      char mli_program [ 24 ] ;
>
> }  ;
>
> struct Menu_Set
> {
>      char menu_heading [ 12 ] ;     /* Also used as Menu ID */
>      int menu_item_count ;          /* How many Line items ? */
>      menulineitem menusetlineitem [ 18 ] ;
>      menustat menuset_status ;
> }  ;

I prefer to put my typedefs after the structure definitions - the way 
you've done it, my first thought is that the structs are defined 
elsewhere and I started to complain about a missing "extern" 
keyword. I also don't use the tag. Rather:

struct {
 char menu_heading[12];
 int menu_item_count;
 menulineitem menusetlineitem[18];
 menustat menuset status;
} Menu_Set;

Personally, I'd also lose the "magic" numbers and use constants
for the array sizes, because constants are easier to read and *way*
easier to maintain than magic numbers. Thus:

 #define MENU_HEADSIZE 12
 [...]
 char menu_heading[MENU_HEAD_SIZE];
>
> Menu menuStack[64];  /* We can have 64 menu's per system */
> Menu *menuptr;       /* Pointer to the MenuStack */
> Menu *currentMenu ;  /* Pointer to WHICH is current */
> menustat *MenuStatus /* pointer to Menu Status stuff */
> menulineitem *MenuItem;  /* Pointer to the menulineitem */
> int active_menu ;    /* COunter of active menu's set up */
>
> ---------------------------------------------------------------------
>--------- int idx, midx ;
>
> for ( midx = 0 ; midx < active_menu ; midx++
> {
>
> /* < -- Start of PFM maybe ? */
>   menuptr = &menuStack[midx];
>   MenuStatus = &menuptr->menuset_status ;
>
> /* Ok, watch WHAT I do here .... */
>   MenuStatus->ms_counter = 0 ;
>
>   for ( idx = 0; idx < menuptr->menu_item_count; idx++, mrows++ )
>          {
>
> /*   PAY CLOSE ATTENTION TO THE BELOW MenuItem CODE !!!!!!!! */
>
>            MenuItem = &menuptr->menusetlineitem[idx];  /* <---- LOOK
> CLOSELY !!! */ MenuStatus->ms_counter++ ; /* Again, is this trickery?

Nope. It's a common idiom. Quick, without looking, tell me if the 
pointer dereference happens before or after ms_counter is incremented.
If you know the answer, then the code is fine. If you *don't* know the 
answer, rewrite the code, because I guarantee you won't remember what 
you were thinking 6 months from now. Personally, I think you're asking 
for a rogue pointer to creep in, but I write code the same way I write 
prose: plodding, linear, and step-wise. I'll trade nifty coding for 
clarity every time.

> Notice the MenuStatus and the MenuItem pointers. I can set these to
> directly to the address of the information I need to access. And they
> WORK as should ( I have tested this out).
>
> Now my questions's are:
>
> If this works, why does everone use the "aptr->bptr->item" method. Is
> that more the political correct method? Is there anything BAD or
> BORKEN with doing the way I am doing it?

No. Double levels of indirection with structure pointersare more common 
in the code I usually read and write, especially when trying to 
implement wrapper code that invokes a function through a function 
ponter, which is often what aptr->bptr->item ends up being (that is, 
item is a function pointer, not a scalar data type). The way you're 
doing it, if "item" ends up needing to point at a function one day, 
you'll have to rewrite your code.

Kurt


More information about the Linux-users mailing list