is it any good to use typedef ?

Discussion in 'C Programming' started by dreamcatcher, Sep 19, 2003.

  1. dreamcatcher

    dreamcatcher Guest

    I always have this idea that typedef a data type especially a structure
    is very convenient in coding, but my teacher insisted that I should use
    the full struct declaration and no further explanations, so I wonder is
    there any good using typedef ? and I also know that when a data type
    being typedefed become an abstract data type, so what exactly is an
    abstract data type, is it any good ?
     
    dreamcatcher, Sep 19, 2003
    #1
    1. Advertisements

  2. Typedeffing structs is a bad idea, but there *are* good uses for
    typedef. Particularly with function pointers.

    Suppose you want a function that takes in an array of function
    pointers (actually a pointer to function pointers) and returns one of
    the function pointers it got. These functions each take multiple
    parameters and return one value. (Suppose they are of the form int
    function(int, int).)
    How would you write the prototype for this kind of function? Without
    typedef, it *is* possible, but I'm not even going to try it. Some C
    expert will provide you one.
    However, with typedef, it's easy:
    typedef int (*func_ptr)(int, int);
    func_ptr selectOneOfTheFunctions(func_ptr functions[]);

    --
    /-- Joona Palaste () ---------------------------\
    | Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
    | http://www.helsinki.fi/~palaste W++ B OP+ |
    \----------------------------------------- Finland rules! ------------/
    "You could take his life and..."
    - Mirja Tolsa
     
    Joona I Palaste, Sep 19, 2003
    #2
    1. Advertisements

  3. I am afraid this subject is pretty holy-warish. At any rate, let me
    disagree with you. There are occurences of good usage for a typedef'd
    structure. Let's say you are creating an abstract data type, foo. You
    can create an objet of type foo, destroy an objet of type foo and bar an
    objet of type foo. For now you choose to implement foo as a struct, but
    this is not required by your interface design. The one good way I know
    of how to do that is to offer the following interface:

    /*-------------------8<---foo.h------------------------------*/
    #ifndef FOO_H
    #define FOO_H

    typedef struct foo_tag foo;

    foo *foo_create(void);
    void foo_bar(foo *f);
    void foo_bar(foo *f);

    #endif /* FOO_H */
    /*-------------------8<---foo.h-----------------------------*/

    /*-------------------8<---foo.c-----------------------------*/
    #include <stdlib.h>
    #include "foo.h"

    struct foo_tag
    {
    int baz;
    };

    foo *foo_create(void)
    {
    foo *f;
    f = malloc(sizeof *f);
    if (NULL != f)
    {
    f.baz = 0;
    }
    return f;
    }

    void foo_bar(foo *f)
    {
    f.baz++;
    }

    void foo_destroy(foo *f)
    {
    free(f);
    }
    /*-------------------8<---foo.c-----------------------------*/

    The day you refactor your code and find out that foo is much better
    doing as an unsigned long than a structure, then all you have to do is
    change the typedef line in your header and rewrite your implementation,
    and, O gloria, allelluya, your interface hasn't changed !

    I'd be interested to hear your arguments (if any) for why it is not a
    good idea to typedef the struct in this case...
    Yes indeed ;-)
     
    Bertrand Mollinier Toublet, Sep 19, 2003
    #3
  4. dreamcatcher

    Eric Sosman Guest

    Using or avoiding typedef with struct and union types
    seems to be a matter of taste. I haven't seen any solid
    technical reason to favor one practice over the other, so
    it comes down to "de gustibus." (Personally, I'm in the
    use-the-typedef camp -- but I have no particular quarrel
    with people who feel otherwise.)

    In addition to Joona's example of using typedef to
    clarify gnarly function declarations, another place I find
    typedef useful is in accommodating the uncertainties about
    the sizes of C's types. For example, if I need an integer
    type capable of representing values up to one million, it
    is unsafe to use `int' because it might only go as high as
    32767. `long' will go to at least 2147483647 and will
    therefore suffice, but on some machines `long' will be
    serious overkill and a waste of space. If I need to store a
    large quantity of these numbers, I'd like to use the smallest
    possible type.

    Preprocessor tests coupled with typedef provide a way to
    handle this portably and with minimal ugliness:

    #include <limits.h>
    #if CHAR_MIN <= -1000000 && 1000000 <= CHAR_MAX
    typedef char Million;
    #elif SHRT_MIN <= -1000000 && 1000000 <= SHRT_MAX
    typedef short Million;
    #elif INT_MIN <= -1000000 && 1000000 <= INT_MAX
    typedef int Million;
    #else
    typedef long Million; /* known to suffice */
    #endif

    Thereafter, I can just write `Million' whenever I mean "a
    sufficiently but not unnecessarily wide integer:"

    Million *ptr = malloc(1234567 * sizeof *ptr);
    Million smallest, largest;
    Million func(void);

    .... and so on; the result of all the grungy decision-making
    has been conveniently packaged into the single word `Million'.

    One shortcoming, though, is illustrated by this code:

    Million value = 42;
    printf ("value = %d\n", value); /* WRONG */

    The problem is that if `Million' actually turns out to be an
    alias for `long', the "%d" format specifier ought to be "%ld"
    instead. One way to deal with this is to define a FMT_MILLION
    macro as either "d" or "ld" in the testing above; you could
    then write

    printf ("value = %" FMT_MILLION "\n", value);

    This works, but is clumsy to write and makes a mess for some
    kinds of tools that assist with translating message strings
    to multiple languages. I prefer the simpler

    printf ("value = %ld\n", (long)value);

    .... even though it may cost a little more at run time.

    In short: typedef is convenient when you'd like to hide
    the details of some type decisions from the eventual user
    (possibly yourself).
     
    Eric Sosman, Sep 19, 2003
    #4
  5. dreamcatcher

    John Bode Guest

    Why? It's done in the standard library (see FILE). I've done it
    quite a bit over the years. Why, exactly, is it a bad idea?
    Now you *know* this is a challenge that must be met...

    f -- f
    is an array -- f[]
    of pointers -- *f[]
    to functions -- (*f[])()
    taking two int parameters -- (*f[])(int, int)
    returning int -- int (*f[])(int, int)

    g -- g
    is a function -- g()
    taking an array of pointers
    to functions with two int
    parameters returning int -- g(int (*f[])(int, int))
    that returns a pointer to a
    function -- (*(g(int (*f[])(int, int))))()
    taking two int parameters -- (*(g(int (*f[])(int, int))))(int, int)
    returning int -- int (*(g(int (*f[])(int, int))))(int,
    int)

    I think that's right.

    Perfectly transparent.
    Really, where's the fun in that?
     
    John Bode, Sep 19, 2003
    #5
  6. typedefing pointers to structs is dangerous because the user may not
    realise its a struct.
     
    Mark McIntyre, Sep 20, 2003
    #6
  7. dreamcatcher

    Kevin Easton Guest

    In the case of FILE it's appropriate, because you don't need to realise
    it's a struct - you only ever manipulate pointers-to-FILE, and never
    FILEs themselves. Any opaque data type you create yourself can be
    similarly hidden behind a typedef without problems, but a transparent
    data type probably shouldn't be.

    In these matters I normally like to follow the example of the standard
    library - an example of where a typedef should be used is the aformentioned
    FILE, and an example of where a typedef shouldn't be used is struct tm.

    - Kevin.
     
    Kevin Easton, Sep 20, 2003
    #7
  8. dreamcatcher

    Jack Klein Guest

    You realize, I hope, that the current C standard has done all of this
    work for you?

    You can include <inttypes.h> and use:

    int_least32_t value;

    ....to define your type, and:

    printf ("value = %" PRIdLEAST16 "\n", value);

    ....to print it, without creating your own type definitions and macros?

    Note that it is quite possible and relatively easy to create your own
    <stdint.h> and <inttypes.h> headers, at least up to 32 bit types, for
    any conforming C89/90 compiler? If you do it properly all code that
    uses them will still work just fine on an actual C99 compiler that
    provides them.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c++-faq-lite/
    alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
     
    Jack Klein, Sep 20, 2003
    #8
  9. dreamcatcher

    Jack Klein Guest

    Here's the one place I agree with you. Our coding standards, which I
    had a large part in creating, specifically forbid creating a typedef
    for a pointer to any type of object, not just structures.

    On the other hand, typedefs are required for all pointers to
    functions.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c++-faq-lite/
    alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
     
    Jack Klein, Sep 20, 2003
    #9
  10. This is probably the key - if you never actually need to know the
    structure of the struct, then hiding a pointer to it in a t ypedef is
    safe enough.
     
    Mark McIntyre, Sep 20, 2003
    #10
  11. Not just convenient, but also sensible IMHO for structs. Not pointers,
    though - it's better not to hide them behind LPFOO nonsense.
    Sure, but you might want to wait until you've finished your course before
    going that route.
    Er, no, not really.
    "A set of data values, together with a set of operations on those values
    that is defined without reference to the representation of the data values,
    is called an abstract data type."
    (Bruce J Maclennan, "Principles of Programming Languages".)

    In C, opaque types form a relatively close approximation to this idea.
     
    Richard Heathfield, Sep 20, 2003
    #11
  12. dreamcatcher

    Ben Pfaff Guest

    For what it's worth, a typedef is required for use of va_arg with
    some types, e.g. pointer-to-function types.
     
    Ben Pfaff, Sep 22, 2003
    #12
  13. dreamcatcher

    John Bode Guest

    True, but there are times when I don't want the user to be able to
    access or manipulate struct members directly. That's why when I do it
    I present it as an ADT that cannot be directly manipulated, and
    provide the functional interface necessary to use it.
     
    John Bode, Sep 22, 2003
    #13
  14. dreamcatcher

    Dan Pop Guest

    Where does the standard say that FILE is a struct?
    When done for type saving purposes, it is a bad idea because it reduces
    the code readability. It always helps to see a struct declaration
    looking like a struct declaration.

    When done for creating an abstract data type, like FILE, it is, of course
    a good idea: it doesn't matter what's behind the typedef: it may be a
    struct or it may be something else, the programmer should not care.

    Dan
     
    Dan Pop, Sep 22, 2003
    #14
  15. dreamcatcher

    John Bode Guest

    Forgive me. I committed the cardinal sin of assuming a particular
    implementation. Of course FILE doesn't have to be implemented as a
    struct.
    Ah. I was thinking exclusively in terms of ADTs. I almost never use
    structs in any other capacity.
     
    John Bode, Sep 23, 2003
    #15
    1. Advertisements

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.