Typedef question

Discussion in 'C Programming' started by mdh, Sep 2, 2008.

  1. mdh

    mdh Guest

    A quick ? :) question about Typedefs.
    There is a very brief discussion about this in K&R ( p146). Googling
    this group, there is a surprising dearth of questions about these.
    From one of the threads, there is sound advice ( to me at any rate)
    not to hide pointers behind typedefs.
    So, may I ask the group when the use of typedefs really makes sense?

    Sorry if this is somewhat general, but there are no exercises ( not
    that I am asking for any!!) provided.
    mdh, Sep 2, 2008
    #1
    1. Advertising

  2. mdh

    Guest

    mdh wrote:
    > A quick ? :) question about Typedefs.
    > There is a very brief discussion about this in K&R ( p146). Googling
    > this group, there is a surprising dearth of questions about these.
    > From one of the threads, there is sound advice ( to me at any rate)
    > not to hide pointers behind typedefs.
    > So, may I ask the group when the use of typedefs really makes sense?
    >
    > Sorry if this is somewhat general, but there are no exercises ( not
    > that I am asking for any!!) provided.


    Typedefs serve at least two main purposes. The most common one is to
    allow you to write code that uses a particular type, when you
    anticipate that the type it should use might be different in different
    contexts. A simple example is size_t, which is a typedef set up by the
    C standard library itself. It might be 'unsigned char' on one
    implementation, and "unsigned long long" on another. However, you
    don't have to make any changes to your code when moving it from one
    implementation to the other, because the change occurs inside the C
    standard headers that typedef size_t..

    The second use I've seen is for simplifying type declarations. If you
    make a lot of use of unsigned char, it's convenient to use

    typedef unsigned char uchar;

    Similarly, it's convenient to use

    typedef struct { int i; double d; } intdouble;

    rather than

    struct intdouble { int i; double d;};

    mainly because it allows you to refer to the type using "intdouble"
    rather than "struct intdouble". This is especially attractive to
    people who are used to C++, where the keyword struct would be needed
    only in the definition of the type, and not when using it.

    And, as you've already seen, typedef can be used to simplify code that
    relies upon function pointers.
    , Sep 2, 2008
    #2
    1. Advertising

  3. mdh

    mdh Guest

    On Sep 2, 12:47 pm, Eric Sosman <> wrote:
    > mdh wrote:
    > > A quick ? :) question about Typedefs.
    > >

    >      One important use for typedef is to deal with the variability
    > of C's native types from machine to machine.
    >      Another important use is to improve readability by decomposing
    > complicated declarations into manageable pieces.
    >
    >


    thank you Eric for that explanation.
    mdh, Sep 2, 2008
    #3
  4. mdh

    mdh Guest

    On Sep 2, 12:50 pm, wrote:
    > mdh wrote:
    > > A quick ? :) question about Typedefs.


    >
    > Typedefs serve at least two main purposes. The most common one is to
    > allow you to write code that uses a particular type.


    > The second use I've seen is for simplifying type declarations. If you
    > make a lot of use of unsigned char, it's convenient to use
    >
    >


    thank you James. Appreciated.
    mdh, Sep 2, 2008
    #4
  5. mdh

    Guest

    On Sep 2, 10:50 pm, wrote:
    > mdh wrote:
    > > A quick ? :) question about Typedefs.
    > > There is a very brief discussion about this in K&R ( p146). Googling
    > > this group, there is a surprising dearth of questions about these.
    > > From one of the threads, there is sound advice ( to me at any rate)
    > > not to hide pointers behind typedefs.
    > > So, may I ask the group when the use of typedefs really makes sense?

    >
    > > Sorry if this is somewhat general, but there are no exercises ( not
    > > that I am asking for any!!) provided.

    >
    > Typedefs serve at least two main purposes. The most common one is to
    > allow you to write code that uses a particular type, when you
    > anticipate that the type it should use might be different in different
    > contexts. A simple example is size_t, which is a typedef set up by the
    > C standard library itself. It might be 'unsigned char' on one
    > implementation, and "unsigned long long" on another. However, you
    > don't have to make any changes to your code when moving it from one
    > implementation to the other, because the change occurs inside the C
    > standard headers that typedef size_t..
    >
    > The second use I've seen is for simplifying type declarations. If you
    > make a lot of use of unsigned char, it's convenient to use
    >
    > typedef unsigned char uchar;


    Ugh. I don't really like code that does that. Also code that has u8,
    uchar8 etc.
    IMHO typedef is not there to save you typing. You could edit your
    editor so whenever you type `uchar ' it replaces it with unsigned
    char.
    , Sep 2, 2008
    #5
  6. mdh

    Guest

    In article <1220384800.358284@news1nwk>,
    Eric Sosman <> wrote:

    > Finally, the pointer thing. Even when a library traffics in
    >pointers to private structs, the fact that they're pointers is usually
    >something the caller must know, if for no other reason than to test
    >a returned value against NULL. For this reason, I'd prefer to say
    >that a function returns a `HashItem*' than a `HashItemPointer'; the
    >latter just makes it harder to discern what you're dealing with.
    >(Is this stance inconsistent with my preference for `HashItem' over
    >`struct hashItem'? Probably, but as I said earlier I'm not going to
    >war over it.)


    I disagree that this is inconsistent; since pointerness is important
    for the user-programmer to know about, revealing it in the interface
    instead of hiding it behind a typedef is an easy way to save the
    user-programmer the trouble of making a trip to the documentation to
    discover it. Revealing structness in the same way doesn't give
    information that's useful (at least, it doesn't if your type is
    actually abstract; if you want to give direct information to (some of)
    the struct members, then the user-programmer also needs to know that
    it's a struct, and in that case hiding structness behind a typedef is
    also a Bad Idea).


    I dislike hiding both properties behind typedefs; but my dislike for
    hiding structness is a purely aesthetic dislike, and my dislike for
    hiding pointerness is based on strong opinions about The Way Things
    Should Be and on experience with how useful it is to have the
    information in front of me while I'm editing code.


    dave

    --
    Dave Vandervies dj3vande at eskimo dot com
    I am Aquarion, I am everywhere. There are only 120 real people on the
    Internet, and I'm three of them.
    --Aquarion in the scary devil monastery
    , Sep 2, 2008
    #6
  7. mdh <> writes:
    > A quick ? :) question about Typedefs.
    > There is a very brief discussion about this in K&R ( p146). Googling
    > this group, there is a surprising dearth of questions about these.
    > From one of the threads, there is sound advice ( to me at any rate)
    > not to hide pointers behind typedefs.
    > So, may I ask the group when the use of typedefs really makes sense?
    >
    > Sorry if this is somewhat general, but there are no exercises ( not
    > that I am asking for any!!) provided.


    A typedef creates an alias (a name consisting of a single identifer)
    for an existing type.

    Strictly speaking, typedefs are almost never necessary. (The one
    exception, I think, involves the va_arg macro for variadic functions,
    which requires a type name that can be used in a certain way.)

    It's very common to create a typedef for a struct type. In my opinion
    (which plenty of smart programmers don't share), this is poor style.
    For example, given:

    struct foo {
    /* member declarations */
    };

    the type already has a perfectly good name, "struct foo". Why create
    another one? The counterargument is that it's more convenient to have
    a simple single-identifier name for the type.

    The syntax for function types and pointer-to-function types is
    sufficiently convoluted that it can be worthwhile to simplify it by
    using typedefs. For example if you want a pointer to a function that
    takes a double argument and returns a double result, you can write:

    double (*ptr)(double);

    or you can write:

    typedef double math_func(double);
    math_func *ptr;

    Or, if you prefer, you can write:

    typedef double (*math_func_ptr)(double);

    Hiding pointerness behind a typedef is usually a bad idea, but in the
    case of a pointer-to-function type it's more defensible.

    A typedef is also appropriate when you want an abstract data type,
    where code that uses the type shouldn't know anything about its
    internals. The type FILE, declared in <stdio.h> is a good example.
    (The use of all-caps isn't particularly consistent with modern style,
    which uses all-caps for macros, but it's been around for a very long
    time.)

    And typedefs are often appropriate for numeric types. I *don't* mean
    something like

    typedef unsigned int uint;

    which does nothing but save you a little typing. I'm referring to a
    weaker form of data abstraction, where code that uses the typedef
    knows that it's an integer type, and whether it's signed or unsigned,
    but doesn't need to know *which* predefined type because it can vary
    from one system to another.

    To summarize:

    Use a typedef when the internal characteristics of the type are
    irrelevant to code that uses it (e.g., FILE).

    Use a typedef when a named type can be implemented differently on
    different systems (e.g., int32_t, size_t).

    Use a typedef to give a name to something that can otherwise only be
    referred to by some complicated syntax, particularly in the case of
    function types and pointer-to-function types.

    If you're using a typedef just to save a few keystrokes, don't bother.
    Given "typedef unsigned int uint;", uint can never be anything other
    than unsigned int; just use its real name, "unsigned int". And if
    uint *can* be something other than unsigned int, "uint" is a lousy
    name.

    Don't bother with typedefs for struct types unless you're doing the
    kind of data abstraction I discussed above -- but reasonable people
    differ on this.

    And I can think of at least one exception to the above. I don't mind

    typedef unsigned char byte;

    "byte" can never be anything other than unsigned char, but assigning
    the name "byte" can make the usage clearer (i.e., this is raw data,
    not necessarily characters).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Sep 3, 2008
    #7
  8. writes:
    [...]
    > The second use I've seen is for simplifying type declarations. If you
    > make a lot of use of unsigned char, it's convenient to use
    >
    > typedef unsigned char uchar;

    [...]

    IMNSHO it's not convenient enough to justify using a typedef rather
    than just typing "unsigned char". For one thing, if I'm reading code
    that uses "uchar" I'll always have a nagging suspicion that somebody
    has decided it would be a cute idea to define it as something other
    than unsigned char (say, unsigned short or wchar_t).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Sep 3, 2008
    #8
  9. mdh

    Thad Smith Guest

    mdh wrote:

    > So, may I ask the group when the use of typedefs really makes sense?


    Yes, you may. ;-)

    In addition to the uses already described, I use typedefs for
    documentation. For example, I may define a specific type, used in several
    places, that is implemented as an unsigned int, but carries specific
    attributes. For example,

    typedef unsigned int tTimeout; /* timeout interval in ms, 0=none */

    When I declare a variable of type tTimeout, I don't need to repeat the
    measurement units and special meaning of 0, since it is inherited from the
    typedef.

    --
    Thad
    Thad Smith, Sep 3, 2008
    #9
  10. Richard Heathfield <> writes:

    > Keith Thompson said:
    >
    > <snip>
    >
    >> It's very common to create a typedef for a struct type. In my opinion
    >> (which plenty of smart programmers don't share), this is poor style.
    >> For example, given:
    >>
    >> struct foo {
    >> /* member declarations */
    >> };
    >>
    >> the type already has a perfectly good name, "struct foo".

    >
    > That's *two* names, one of which seems rather pointless.


    *one* name, with two parts. Both parts are needed to unambiguously
    refer to the type in question, lest you get the wrong struct or foo.

    I would expect you of all people in this place to understand the
    difference, Richard.

    > Yes, opinions certainly do vary on this!


    Both approaches have merit.

    mlp
    Mark L Pappin, Sep 4, 2008
    #10
  11. mdh

    Guest

    On Sep 2, 2:47 pm, Eric Sosman <> wrote:
    > mdh wrote:
    > > A quick ? :) question about Typedefs.
    > > There is a very brief discussion about this in K&R ( p146). Googling
    > > this group, there is a surprising dearth of questions about these.
    > > From one of the threads, there is sound advice ( to me at any rate)
    > > not to hide pointers behind typedefs.
    > > So, may I ask the group when the use of typedefs really makes sense?

    >
    > One important use for typedef is to deal with the variability
    > of C's native types from machine to machine. For example, Park and
    > Miller's "Minimal Standard Random Number Generator" uses numbers as
    > large as 2147483646. Many machines' int type will suffice for this
    > magnitude, but on some you may need to resort to long. You could
    > just use long everywhere in the code, but on some machines that may
    > be overkill. Here's a possible solution:
    >
    > #include <limits.h>
    > #if INT_MAX >= 2147483646
    > typedef int MSint; /* int is enough */
    > #else
    > typedef long MSint; /* int too small; use long */
    > #endif
    >
    > ... and then write the code using MSint throughout. The typedef
    > encapsulates your choice of the appropriate native type to use in
    > the environment at hand. It doesn't solve every problem -- for
    > example, if you use printf() or scanf() with these numbers, you
    > need to choose the right format strings -- but it can smooth out
    > a good many machine-to-machine differences.
    >
    > Another important use is to improve readability by decomposing
    > complicated declarations into manageable pieces. The classic example
    > of this is the declaration of the signal() function:
    >
    > void (*signal(int sig, void (*func)(int)))(int);
    >
    > Most people will find the code more readable if a typedef is used
    > (there's more than one way to do this):
    >
    > typedef void (SigHandler)(int sig);
    > SigHandler *signal(int sig, SigHandler *func);
    >
    > Another use is to attach suggestive one-word names to struct
    > and union types, as in
    >
    > typedef struct hashItem {
    > unsigned int hashValue;
    > const void *itemPointer;
    > struct hashItem *nextItem;
    > } HashItem;
    >
    > People differ about whether this is a good idea or not. Some feel
    > that the struct-ness of the thing cannot be hidden (you're going to
    > use . and -> with it, after all), so the attempt to hide it is
    > feeble and maybe even obfuscatory. Others feel that it's quicker and
    > easier to write and read `HashItem' than `struct hashItem', and that
    > using the shorter phrase improves readability. I'm in the latter camp
    > (especially when the nature of the struct or union is private to a
    > library and only a `HashItem*' is exported to the clients), but my
    > preference isn't so strong that I'd take up arms against the
    > unbelievers. You'll have to consult your own tastes on this one.
    >
    > Finally, the pointer thing. Even when a library traffics in
    > pointers to private structs, the fact that they're pointers is usually
    > something the caller must know, if for no other reason than to test
    > a returned value against NULL. For this reason, I'd prefer to say
    > that a function returns a `HashItem*' than a `HashItemPointer'; the
    > latter just makes it harder to discern what you're dealing with.
    > (Is this stance inconsistent with my preference for `HashItem' over
    > `struct hashItem'? Probably, but as I said earlier I'm not going to
    > war over it.)
    >


    This things apply for simple programs, but if you're defining
    something like abstract types (which is almost the rule for real
    programs), you're *not* going to apply the . or -> operators to it,
    and callers do not need to know whether it's a pointer or anything
    else, hence they're not going to test it against NULL. Doing so only
    makes it difficult to change the program later, should you decide to
    change what the type actually represents. That's partly the essence of
    abstraction: you know that a variable of the type (an "instance") has
    a state that is controlled by the functions provided for the abstract
    type, but you don't know what it is or how it's implemented.

    Sebastian
    , Sep 4, 2008
    #11
  12. mdh

    Guest

    On Sep 4, 7:50 am, Eric Sosman <> wrote:
    > wrote:
    >> On Sep 2, 2:47 pm, Eric Sosman <> wrote:
    >>> [... concerning typedef'ed aliases for struct types ...]
    >>> People differ about whether this is a good idea or not.  Some feel
    >>> that the struct-ness of the thing cannot be hidden (you're going to
    >>> use . and -> with it, after all), so the attempt to hide it is
    >>> feeble and maybe even obfuscatory.  Others feel that it's quicker and
    >>> easier to write and read `HashItem' than `struct hashItem', and that
    >>> using the shorter phrase improves readability.  I'm in the latter camp
    >>> (especially when the nature of the struct or union is private to a
    >>> library and only a `HashItem*' is exported to the clients), [...]

    >
    >>>      Finally, the pointer thing.  Even when a library traffics in
    >>> pointers to private structs, the fact that they're pointers is usually
    >>> something the caller must know, if for no other reason than to test
    >>> a returned value against NULL.  [...]

    >
    >> This things apply for simple programs, but if you're defining
    >> something like abstract types (which is almost the rule for real
    >> programs), you're *not* going to apply the . or -> operators to it,
    >> and callers do not need to know whether it's a pointer or anything
    >> else, hence they're not going to test it against NULL. Doing so only
    >> makes it difficult to change the program later, should you decide to
    >> change what the type actually represents. That's partly the essence of
    >> abstraction: you know that a variable of the type (an "instance") has
    >> a state that is controlled by the functions provided for the abstract
    >> type, but you don't know what it is or how it's implemented.

    >
    >      It looks like we agree that typedef'ed aliases for structs
    > can be pleasant, particularly when the internals of the struct
    > are hidden from the user.  But it also looks like we disagree
    > about typedef'ed aliases for the pointers to them: You (if I
    > understand correctly) like a library that deals in a completely
    > opaque data type whose pointer-ness is not exposed, while I
    > prefer to deal with known-to-be-pointers to opaque data.
    >
    >      Both positions are reasonable, but I prefer mine (surprise!)
    > because returning NULL to indicate a failure is a mechanism C
    > programmers will find familiar, having been accustomed to the
    > pattern in their use of things like fopen().  My way:
    >
    >         /* in a header */
    >         typedef struct opaque_struct ADT;  /* no * */
    >         ADT *makeADT( ...parameters... );
    >
    >         /* in a caller's code */
    >         ADT *adt = makeADT(...);
    >         if (adt == NULL) ...
    >
    >      If you want to hide (or at least not advertise) the pointer-
    > nature of makeADT's value, I think you either need to invent a
    > separate channel for the status:
    >
    >         /* in a header */
    >         typedef struct opaque_struct *ADT;  /* note the * */
    >         int makeADT(ADT*, ...parameters... );
    >
    >         /* in a caller's code */
    >         ADT adt;
    >         if (makeADT(&adt, ...) < 0) ...
    >


    That's what I usually do. Though in your own framework you won't
    usually return int for error/success codes, but instead define your
    own error/success type, like for example Mozilla's 'nsresult' type,
    and NS_OK, NS_ERROR_OUT_OF_MEMORY, etc. codes for that type. That
    allows you to express more specifically what kind of error happened.
    Also, I usually follow the convention that the "creator" of the ADT
    takes a pointer, and the rest don't:

    someresult CreateMyADT(ADT *);
    void DestroyMyADT(ADT);

    void DoXToADT(ADT);
    void DoYToADT(ADT);
    void DoZToADT(ADT);

    > ... or else you need to hide the details of the comparison:
    >
    >         /* in a header */
    >         typedef struct opaque_struct *ADT;
    >         ADT makeADT( ...parameters... );
    >         #define isValidADT(adt) ((adt) != 0)
    >
    >         /* in a caller's code */
    >         ADT adt = makeADT( ... );
    >         if (! isValidADT(adt)) ...
    >
    > ... or maybe you've got another idea I haven't thought of?
    >
    >      A separate channel for status has some merit: OpenVMS
    > uses that style almost everywhere.  And it can't be denied
    > that the C library's fondness for "return a special value"
    > leads to clumsiness in certain places: strtod(), getc(),
    > islower(), and so on.  But using NULL as a special value
    > seems to me both unobjectionable and convenient.
    >
    >      Using NULL without admitting it (by inventing isValidADT
    > or something of the sort) strikes me as hiding for hiding's
    > sake, the very definition of obfuscation.  Yes, there's a
    > certain sort of angelic purity in doing so, but it makes me
    > wonder whether the means has somehow become an end.
    >


    Well, probably the only advantage of doing things like that "without
    admitting it" is that the type might later be changed to represent
    something else and then testing against NULL would be no longer
    appropriate. But if the program follows some kind of convention and
    there's little chance that it might be changed, then that advantage
    would disappear and it would be OK to test against NULL.

    Sebastian
    , Sep 5, 2008
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. JustSomeGuy
    Replies:
    1
    Views:
    335
    Mike Wahler
    Sep 20, 2003
  2. James Brown

    typedef question

    James Brown, Nov 16, 2005, in forum: C Programming
    Replies:
    3
    Views:
    439
    James Brown
    Nov 16, 2005
  3. Tony Johansson
    Replies:
    7
    Views:
    346
    Victor Bazarov
    Aug 16, 2005
  4. Alex

    typedef question

    Alex, Nov 28, 2005, in forum: C++
    Replies:
    6
    Views:
    458
    Alex O.
    Dec 2, 2005
  5. oor
    Replies:
    0
    Views:
    1,343
Loading...

Share This Page