Re: structs help

From: Chris Torek (nospam_at_torek.net)
Date: 04/04/04


Date: 4 Apr 2004 15:42:17 GMT


>"Leor Zolman" <leor@bdsoft.com> wrote in message
>news:kf5v60tim95vloilch7r6f9hojkbhf8tsi@4ax.com...
>>I used the same name for the typedef as for the structure tag, because
>>that happens to me my own personal style; you might choose to do
>>otherwise, but this is perfectly legal.

In article <news:byTbc.55128$mU6.230300@newsb.telia.net>
Chris Fogelklou <chris.fogelklou@comhem.se> writes:
>Although some compilers don't like it (even if it is legal!)
>
>I've had to go through code written for one compiler and edit all the struct
>definitions for another one because all of the structures defined used the
>same name and the second compiler didn't like it.
>
>This was for an embedded system... can't remember the specific compiler...

The C standards (original ANSI C89, ISO C90, and ISO C99) are quite
clear: structure tag names are in a separate name space and *must*
not interfere with any other identifiers in the ordinary name space
used for variables, functions, and typedef-names. So this particular
compiler was just plain broken.

Of course, if you have to use a broken tool, you have to use a
broken tool. :-) But I would put this next bit differently:

>anyway, for best code portability, use different names:
>
>typedef struct my_struct_tag {
> int my_int;
> float my_float;
>} my_struct_t, *p_my_struct_t;

As I like to point out, the real problem with typedef is that it
lies to humans and confuses them.

First, the keyword itself has the wrong name: it does not define
a type, but rather changes variable declarations into aliases for
some existing type(s):

    int a, *b, c[3]; /* declare a as int, *b as int (and thus
        b as pointer to int), c[i] as int (and thus c as array of
        int, with the number of elements in the array being 3) */

    typedef int a, *b, c[3]; /* change the above "declare ... as"
        to "declare ... as an alias for": a is an alias for int,
        b is an alias for pointer-to-int, and c is an alias for
        array-3-of-int. */

This is even more pronounced in the "typedef struct ..." sequence,
where people seem to believe that the typedef is creating the new
type. It is not -- it is the "struct ..." part that creates the
new type.

Second, the syntax for using a typedef'ed name is also confusing.
As I noted in an earlier posting, it becomes impossible to look at
a code fragment and decide a priori whether something is a declaration:

    int(i),(*p)[3]; /* just to show parentheses in declarations */
    zorgle(blat);

The second line, which looks like a function call, changes meaning
if "zorgle" is a typedef:

    typedef char *zorgle;
    ...
    zorgle(blat); /* same as "char *blat; */

(Of course, if this code appears outside of a function, a function
call is not allowed here anyway -- at least, not in C. Other languages
that strongly resemble C *do* allow function calls in such positions.)

As with macros like:

    #define MIN(a, b) ((a) < (b) ? (a) : (b))

typedef-names can surprise one if one is not aware that they *are*
typedef-names, so it is often wise to choose some marker to say
"beware, this is a typedef-name" -- just as many C programmers
write the MIN macro above in uppercase, to let other programmers
know that:

    i = MIN(read_input(), x++);

is unlikely to do anything good.

The "typedef suffix" _t in Chris Fogelklou's examples is just such
a marker. If one uses it consistently, one can recognize:

    zorgle_t (blat);

as a declaration (with unnecessary parentheses) without having to
go look to see whether zorgle_t is in fact a typedef. The _t suffix
tells you that it must be. (If it is not, the code is simply wrong
and needs to be fixed.)

My own preferred method is to type out the keyword "struct" each
time. I do have one exception to this: if a type-name is going to
be used heavily within a given program, so that anyone working on
that program is going to have to be aware that it *is* a type-name,
then it becomes OK to use a shorter name, even without any special
syntactic markings (such as an _t suffix or leading uppercase
letter).

The idea here is that I expect anyone working on *any* C program
to know that the C integral types are char, short, int, long, and
their explicit-sign variants (e.g., signed char and unsigned int),
the floating point types are float, double, and long double, and
for C99, the whole series of complex types, and so on. At the same
time, though, I expect any programmer working on the zorgle program
to know that the zorgle system uses a "zorgle" type with various
"semi-abstract datatype" features. If the program happens to use
some ancillary internal types in places, those might just have to
spell out the word "struct", and I might even use "struct zorgle"
anyway for the "well-known" zorgle type -- but because the type is
pervasive, it is OK to relax the "spell out the struct keyword"
rule.

This is, of course, a matter of taste. C *compilers* can keep
straight which identifiers have been typedef-aliased; whether you,
as a C programmer, choose some set(s) of rule(s) to make sure
that mere humans can also keep them straight is up to you.

-- 
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.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.


Relevant Pages

  • Re: [PATCH 1/1] LinuxPPS: Pulse per Second support for Linux
    ... Follows my comments and then the patch, hope now I can came back into ... +typedef union pps_timeu { ... +typedef struct pps_info { ... different version of the compiler, and when different compiler options are ...
    (Linux-Kernel)
  • Re: Process dump facility public API - pdpublic.h
    ... struct _PDOPTIONS *pSystemDefaults; /* Ptr to System Defaults struct */ ... typedef DDPREQUEST *PDDREQUEST; ... also be specified in the DDPREQUEST flags. ... /* PDUNION is used in both the PDPROCESS and PDPROCESS2 structures. ...
    (comp.os.os2.bugs)
  • Re: advantage of using typedefs
    ... The underlying problem / solution here is "abstraction". ... struct, ... possible to call this with a length or pressure measurement by ... typedef double temperature; ...
    (comp.lang.c)
  • Re: syntax errror
    ... >>> int maxGrey' ... >> declaration of maxGrey. ... typedef double; ... struct some_tag_name { ...
    (comp.lang.c)
  • [bug] typedefed base class not visible [VC8 RTM.050727-4200]
    ... Most of it boils down to the following new compiler bug: ... typedef B::base base; ... but I'd really hate to need to refactor ALL client code.. ...
    (microsoft.public.dotnet.languages.vc)