Could you explain this typedef to me?

Discussion in 'C Programming' started by fl, Feb 2, 2014.

  1. fl

    Jorgen Grahn Guest

    True, but what I tend to see in code which typedefs everything is that
    they either omit the tag, or pick an ugly name. If they have a rule
    "typedef name is tag name" then I don't mind so much.
    Yes, but then you often want a forward declaration -- if you don't need
    the full struct definition and don't want to needlessly pull in header

    Jorgen Grahn, Feb 6, 2014
    1. Advertisements

  2. fl

    Eric Sosman Guest

    I don't understand. If you're not using "the full struct
    definition" and you're not treating it as an opaque type, just
    what are you doing? And, er, how?
    Eric Sosman, Feb 6, 2014
    1. Advertisements

  3. fl

    Tim Rentsch Guest

    It seems like your complaint is not with using typedef names for
    structs but with badly done header files. Good design practice
    would be to provide a separate header file just for the types of
    the module, for exactly the reason you state. Anyone who has
    looked through the tangled mess in /usr/include show understand

    A similar comment applies to structs defined without tags. If it
    is useful to be able to name a particular struct type without
    making use of its content (eg, in 'struct foo*'), then a forward
    declaration should be provided separably from its content. That
    may entail one additional higher strata of header file, for the
    forward declarations, if it is also important to access the type
    definitions separately from the modules data/function definitions.
    (Obviously there are other workable schemes besides having two or
    three separate header files; the important thing is a capability
    for getting just type definitions or declarations without all the
    other baggage.)

    The trick of using 'struct foo*' without #include'ing its header
    (<editorial>a questionable practice</editorial>) obviously won't
    work with with typedef'ed tagless structs, but when there are tags
    things are looking up: the new rule in C11 allows a typedef like

    typedef struct foo_s Foo;

    to be repeated in a translation unit, which would allow you to
    forward declare a typedef'ed struct even if subsequently the
    module's header were #include'ed.
    Tim Rentsch, Feb 7, 2014
  4. fl

    Jorgen Grahn Guest

    I'm treating it as an opaque type -- surely I never said I didn't?

    I am a bit puzzled by this thread, because I initially thought it was
    for the benefit of newbies -- that I only explained something simple
    that all C programmers would know and practice already. But now I'm
    not so sure.

    Let's take a somewhat concrete example. If I write foo.h:

    /* foo.h */
    struct bar_lib;

    struct Foo {
    struct bar_lib* impl;
    // ...

    struct Foo foo_create(void);
    void do_something(struct Foo*);

    foo.h exposes an interface to some functionality, and I chose to use
    the "bar" library to implement it. The foo.h clients can ignore the
    implementation details. Also, I don't want to force these clients to
    pull in barlib.h because it's big and "dirty".

    It's my impression that I cannot accomplish this unless I know the
    struct tag "bar_lib". A typedef won't do: it may be opaque, but I
    cannot use it without pulling in some bar_lib.h header.

    If I misunderstand this I would love to learn about it!

    Jorgen Grahn, Feb 8, 2014
  5. fl

    Eric Sosman Guest

    Apparently not. It seems I read more into what you wrote
    than you put there. (In American usage, when Speaker A says
    "X" and Speaker B responds "Yes, but Y," it usually means that
    Y is an objection to X, that B thinks X is wrong in some way.
    I misunderstood you as denying that the type was opaque, but it
    appears you didn't mean that at all. Sorry!)
    Not sure why this is needed ...
    Is the example realistic? Perhaps so -- Different programmers
    face different demands and address them in different styles, but
    this isn't a style I think I'd choose. Why expose the fact that
    foo depends on bar? That is, why reveal the `struct bar_lib*'
    nature of `impl' to a user of "foo.h"? Considerations:

    - If the user is to use `impl' to get at the innards of the
    `struct bar_lib', he'll need to include "bar_lib.h" anyhow and all
    this name-hiding is for naught. Even if `struct bar_lib' remains
    opaque but the user knows he can use the `impl' element to call
    bar_lib's functions he'll need "bar_lib.h" for their declarations.

    - If the user treats `struct bar_lib' as opaque *and* doesn't
    call any bar_lib functions directly (but always goes through foo),
    then `impl' can be of any struct pointer type at all (because all
    struct pointers smell the same), although this might lead to a lot
    of tedious cast operators in the implementation of foo. `impl'
    could even be a `void*', at the expense of a tiny amount of type

    - When opacity is one of the goals, I usually find it better
    to keep `struct Foo' opaque and have my foo_create() function return
    a pointer to a newly-allocated `struct Foo' rather than a completed
    instance thereof. That way I need reveal nothing whatsoever about
    bar_lib, and am free to adopt the improved xbar_lib without disturbing
    foo's clients.

    Finally, I still don't see what this has to do with "forward
    declarations" or with typedefs -- the string `typedef' is entirely
    absent from the example ...
    Eric Sosman, Feb 8, 2014
  6. fl

    Jorgen Grahn Guest

    Ah, I can see that kind of interpretation now. I should probably have
    written "Yes. But then ...".
    Seems it's not. Must be some habit I picked up; I don't know when or
    where. Based on the warnings gcc shows me, it's needed in a related

    struct bar_lib;
    void foo(struct bar_lib*);
    It's the usual lesson of c.l.c -- you think you only do what
    "everyone" does, and then it turns out they don't.

    I should probably admit here that my primary language is C++. It might
    be the case that this style is more common there. I didn't bring it
    up because it seemed the languages worked the same in this area
    (except you can refer to 'struct Foo' as just 'Foo').
    True. So this isn't the reason. If all users of foo.h will want
    bar_lib.h too, the forwarding above is pointless. The assumption above
    is that users will want to deal with Foo objects, but probably not
    mess with the struct bar_lib.

    'impl' was a badly chosen name -- it makes it sound as if struct Foo
    is just a wrapper for a struct bar_lib. I think it's more realistic
    to assume struct Foo contains a bunch of immediately useful elements,
    /and/ this opaque handle.

    By the way, I now realize a much clearer and simpler example would
    have been something like this:

    // serialize.h
    struct in_addr;
    struct in6_addr;
    struct Foo;
    int serialize_addr(char* buf, size_t len, struct in_addr val);
    int serialize_addr6(char* buf, size_t len, struct in6_addr val);
    int serialize_foo(char* buf, size_t len, struct Foo val);
    // ...
    Yes, although I value my type safety and try to stay clear of void*.
    This is why I shouldn't have used the name 'impl' in the example. Yes,
    if the contents of struct Foo are entirely uninteresting to its
    clients, I would probably make it opaque, too.
    Yes, absent it is. I should have made the purpose of the example more
    clear. My question was "could I have done this without knowing the
    struct tag bar_lib?" and "how would knowing a typedef for it have
    helped me?"

    Jorgen Grahn, Feb 9, 2014
    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.