One very important rule: never use -> in an implementation (.c) file. (By the way, don't use the equivalent *. either.). Dereference operators should only appear in header (.h) files.
Instead, we use accessor macros to get dereference pointers (see the next section for the why). For example,
/* This is the actual implementation */
struct int_stack {
int is_max;
int is_len;
int * is_vals;
};
#define deref_int_stack(_s) (_s)
#define x_max_int_stack(_s) (deref_int_stack(_s)->is_max)
#define x_len_int_stack(_s) (deref_int_stack(_s)->is_len)
#define x_vals_int_stack(_s) (deref_int_stack(_s)->is_vals)
#define max_int_stack(_s) ((void)0, x_max_int_stack(_s))
#define len_int_stack(_s) ((void)0, x_len_int_stack(_s))
#define vals_int_stack(_s) ((void)0, x_vals_int_stack(_s))
Note some syntactic idioms used:
is_).
int_stack).
x_ and the name of the field.
There are several reasons for accessing fields using these multiple levels of macros.
deref_ idiom provides a convenient place to
attach debugging and tracing code for all accesses to this type.
(void)0 construct will (or should) cause a
compile-time warning if a rhs macro is used to modify field.
Note:It turned out that a lot of people were under the misconception that _s was a reserved identifier. It is perfectly legal to use _s, or an identifier that begins with _[lower-case] as a macro parameter. See the standard, or the discussion on comp.lang.c