Could you explain this typedef to me?

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

  1. fl

    James Kuyper Guest

    On 02/03/2014 11:59 AM, Robbie Brown wrote:
    You need to distinguish between defining a struct type, and defining an
    object of struct type:

    // Defining struct types
    struct tag1 { ... };
    typedef struct { ... } name1;
    typedef struct tag2 { ... } name2;

    tag1 and tag2 are struct tags. "struct tag1", name1, "struct tag2", and
    name2 are type names; the last two are different type names for the same
    exact type. Note: they don't have to be different, and it is in fact
    common practice to have the typedef name match the corresponding struct
    tag - doing so reduces some of the differences between C and C++.

    // Defining objects of struct type
    struct tag1 obj2;
    name1 obj3;
    struct tag2 obj4;
    name2 obj5;

    // Defining a struct type and an object of that type in the same
    // definition:
    struct tag3 { ... } obj6;
    struct { ... } obj7.

    Does that clear it up?
    James Kuyper, Feb 3, 2014
    1. Advertisements

  2. fl

    Robbie Brown Guest

    Right, let's see if we can nip this in the bud.

    I'm currently reading four publications concerning C

    Understanding and Using C Pointers
    by Richard Reese

    The Linux Programming interface
    A Linux and UNIX System Programming Handbook
    by Michael KerrisK

    Expert C Programming: Deep C Secrets
    By Peter van der Linden

    and of course the obligatory K&R (ANSI C version)

    Personally I enjoy the social interaction of discussion about all sorts
    of things. I find I learn just as much by talking to people as I do by
    reading. I was simply discussing something that I find interesting.

    I have a standard way of dealing with posts I find irritating or
    irrelevant, I simply don't reply. I don't like arguing, it's a waste of
    time and resolves nothing.

    I've learned a lot about structs thanks to this discussion and have made
    notes on the points raised.

    I hope this clears things up and thank you for your time.
    Robbie Brown, Feb 3, 2014
    1. Advertisements

  3. fl

    Robbie Brown Guest

    I have four struct declarations in my 'learning about structs' file

    typedef struct Foobar{
    int a;
    int b;
    }Foobar, *fbar;

    struct Barbaz{
    int a;
    int b;
    }Barbaz, *bbaz;

    typedef struct{
    long x;
    long y;

    char *cp1;
    char *cp2;

    I have the following 'usages' of these structs

    Foobar fb;
    fb.a = 1;

    fbar fbp = malloc(sizeof *fbp);

    Barbaz.a = 2;
    bbaz = malloc(sizeof *bbaz);

    AArdvark a;
    a.y = 8;

    AArdvark *ap = malloc(sizeof *ap);
    ap -> y = 9;

    Whoami.cp1 = "foobarbaz";

    This all compiles although that's all I've done, not otherwise tested.

    Not at all, I'm having enormous fun, making mistakes and learning.
    Robbie Brown, Feb 3, 2014
  4. fl

    BartC Guest

    Not really. C has all these extra aspects to defining struct types that
    other languages that have records don't have and don't appear to need. And
    with so many extra possibilities, together with the concept of 'tag' names
    (another new idea) having their own namespace, it can get confusing for
    beginners (for others too!). Trying to explain it doesn't make it any
    simpler, or code that mixes all these up less confusing.

    So I try to:

    - Always use typedefs to wrap struct types

    - Not use struct tags

    - Not use anonymous structs

    (But with some exceptions)
    BartC, Feb 3, 2014
  5. Those are not 4 different ways *of doing the same thing*.

    The first defines a struct type, an alias for the struct type, and an
    alias for the corresponding pointer-to-struct type; it defines no

    The second defines a struct type, an object of the struct type, and an
    object of the corresponding pointer-to-struct type.

    The third defines an anonymous struct type and an alias for that type
    (again, it defines no objects).

    The fourth defines an object of an anonymous struct type.

    The unqualified word "struct" or "structure" is commonly used either to
    refer to a struct type or to an object of some struct type. For
    clarity, I suggest avoiding using the word "struct" or "structure" by
    itself, instead using it as an adjective: "struct type", "struct object"
    (also "struct expression", an expression of struct type, and "struct
    value", a value of some struct type). Among other benefits, that would
    probably have avoided the confusion of thinking of those 4 snippets as
    "4 different ways to declare/define a struct".

    Keith Thompson, Feb 3, 2014
  6. fl

    Eric Sosman Guest

    This declares `struct Foobar' in one of the four-minus-one
    ways I listed: With a tag and with its details (its "completion").
    It also declares `Foobar' as an alias for `struct Foobar' and
    `fbar' as an alias for `pointer to struct Foobar', but those are
    just aliases, not declarations of a struct type.
    This declares `struct Barbaz' in the same way `struct Foobar'
    was declared: With a tag and with its innards. It also declares
    a variable `Barbaz' as an instance of `struct Barbaz' and a
    variable `bbaz' as an instance of a pointer to a `struct Barbaz',
    but again: Those are just variables, not declarations of a struct.
    This declares a struct that is untagged and complete, which
    is another of the ways I listed. It also declares `AArdvark' as
    an alias for that struct type.
    Same thing again: This declares an untagged complete struct
    type. It also declares one variable of that type.

    So your "four ways" actually cover two of the three possible
    ways to declare a struct type, twice each. For completeness, the
    third way is

    struct Opaque;

    .... which declares a tagged *in*complete struct type. This way
    could also appear as

    typedef struct Opaque DirtyWindow;
    struct Opaque *makeOpaque(void);
    struct Opaque *kierkegaard = makeOpaque();
    // etc.

    .... but all of these are just uses of the type, not declarations
    of it.
    I get the impression that you're floundering.
    Eric Sosman, Feb 3, 2014
  7. fl

    BartC Guest

    Four ways of creating a 'struct type' though. The following all do the same
    thing: defining a variable d1, d2 etc which is a struct of 3 integers (I've
    had to give each name a different numeric suffix just so I could compile
    them all together):

    struct {int day,month,year;} d0;

    struct date1 {int day,month,year;} d1;

    struct date2 {int day,month,year;};
    struct date2 d2;

    typedef struct {int day,month,year;} Date3;
    Date3 d3;

    typedef struct date4 {int day,month,year;} Date4;
    Date4 d4a;
    struct date4 d4b;

    The last two variables d4a and d4b are compatible. So four or five ways of
    specifying the struct, and four distinct ways of declaring the variables.
    BartC, Feb 3, 2014
  8. fl

    Robbie Brown Guest

    True but there are four of them and they are different, they have
    different forms, contain different numbers of characters and have
    different semantics. My original statement was.

    "So now I appear to have 4 different ways to declare/define a struct.
    I wonder how many more there are"

    I don't think I was suggesting they were four different ways of doing
    the *same* thing unless 'same thing' means declare a(n arbitrary) struct.
    Understood. Thanks for the clear and concise explanation. Are there any
    other ways?
    But they are different aren't they, you yourself explain the differences
    above. If they are not different then they are the same ... but they're
    not are they?

    If they are not four different ways to declare/define a struct and if
    they are not four different ways to do the same thing then what are they?

    Really, I'm not trying to be awkward. What are those four different
    'things' if not ways to declare/define a struct?
    Robbie Brown, Feb 3, 2014
  9. fl

    Eric Sosman Guest

    Let's step *w-a-a-y* back. Consider:

    int x;
    int *xx;
    int xxx[42];
    typedef int xxxx;

    Four declarations, all different: One declares an `int' variable,
    one an `int' pointer, one an array of `int', and the last an
    alias for `int'.

    But `int' is exactly the same in all four. True, one doesn't
    "declare" the `int' type (its declaration is built-in to the C
    compiler and/or language), so the analogy is imperfect. But the
    point Keith and I are trying to make remains the same: What you
    do with a type once it's declared (or built in) doesn't make any
    difference to the declaration (or to the built-in). The "four
    ways" you speak of are just four uses of the struct type, after
    it's declared, not four different ways of declaring a type.
    Eric Sosman, Feb 3, 2014
  10. fl

    Robbie Brown Guest

    Thanks for the great explanation

    Not at all, I'm having enormous fun, making mistakes and learning.
    Robbie Brown, Feb 3, 2014
  11. fl

    James Kuyper Guest

    On 02/03/2014 03:20 PM, BartC wrote:
    True, but the fact that there are several different ways to do that is
    because the different ways differ with regard to things that they do in
    addition to defining those variables.
    This only defines the variables.
    This defines the variables AND defines a struct tag for their type.
    This defines a struct tag for a type.
    This defines variables of a previously defined struct type identified by
    it's tag.
    This defines the variables AND a typedef for their type.
    This defines variables of a previously defined struct type identified by
    it's typedef.
    This defines a struct tag and a typedef name for the same type.

    If you don't want to do multiple things at the same time, you don't have to.

    This is, in principle, no different from the fact that there's several
    different ways to add two numbers, depending upon what else happens in
    the same expression: a++ + b++ is quite different from a+b, which in
    turn is quite different from a-- + b--, but they all add the current
    values of a and b.
    James Kuyper, Feb 3, 2014
  12. fl

    BartC Guest

    Maybe, but sometimes you do just want to declare a variable of a struct
    type, but there are all these possibilies with their subtle differences.

    The way I'm used to defining variables of type T is:

    T a, b, c;

    but with structs, then T might be 'struct Tag' (defined elsewhere), or
    'struct Tag {...} (defined here but useable elsewhere) or struct {...}
    (defined and only useable here) or it might just be a typedef (defined
    elsewhere). These forms are used even when you don't need or want all those
    other things!

    Some type constructors (pointer-to, array-of) are useful to define in-situ,
    rather than have to be formally typedef-ed; and any such constructor will be
    compatible with any identical constructor elsewhere.

    But structs are different! I believe in formally defining structs separately
    and in giving them a name via a typedef, then just using that name:

    T a, b, c;

    (Structs and unions appearing inside another struct or union are different.
    Although they use the same reserved words, I think of them as having a
    somewhere different function (grouping and controlling the layout of
    members). Especially when they are anonymous (not specifying a member name
    for the sub-struct or -union).)
    These are fairly univeral. But C's treatment of structs isn't.
    BartC, Feb 3, 2014
  13. fl

    James Kuyper Guest

    The possibility of using a typedef exists with any type, it's not
    exclusive to structs.
    You don't have to declare a struct tag unless you need it; the same is
    true of a typedef, and you're generally free to choose one or the other.
    You never have to define an object of a given type in the same
    declaration where you define the type - they can always be separated.
    Therefore, I'm not quite sure what you're referring to. You do need to
    understand such constructs if they are written by someone else, but
    that's a different issue.

    You do have to define the struct type somewhere (unless it's one of the
    structs defined in the standard library), which is inherently different
    from, for example, "int". But that is inherent in the fact that it is a
    user defined type.
    Except for function call expressions, C's expressions with both values
    and side effects (a=b, a++, a+=b, etc) are far from universal; I've used
    many languages with no equivalent to any of them: assignment is a
    statement in those languages, not an expression with a value that can be
    used as an operand in another expression. I believe that most of the
    languages which do support them were at least partly inspired by C.
    Without such expressions, it's difficult to construct multiple
    meaningfully different C expressions that calculate a+b.
    James Kuyper, Feb 3, 2014
  14. Not using struct tags in all cases is not an option if you want to have
    a struct containing a pointer to the same type.

    You can *effectively* avoid struct tags by giving them names that you
    won't be tempted to use. For example:

    typedef struct node_s node;
    struct node_s {
    void *data;
    node *prev;
    node *next;

    Or, more simply:

    typedef struct node_s {
    void *data;
    struct node_s *prev;
    struct node_s *next;
    } node;

    Or the above with "node_s" replaced by "node".

    (It's not the way I'd do it, but I've said that enough times
    that I won't repeat the details here.)
    Keith Thompson, Feb 3, 2014
  15. Are there any other ways *to do what*?

    We've seen code that defines a struct type (with or without a tag),
    defines an alias for a struct type, defines an alias for a
    pointer-to-struct type, defines an object of a struct type, and defines
    an object of a pointer-to-struct type. Would defining an object of a
    pointer-to-pointer-to-struct type qualify as "another way"?

    It's particularly difficult to tell what you're asking if you use the
    word "struct" as a noun; it ignores the distinction between a struct
    *type* and a struct *object*.

    There are at least as many different ways to do things as there are
    different things to do.
    Keith Thompson, Feb 3, 2014
  16. fl

    Jorgen Grahn Guest

    I haven't followed the thread closely, but one data point ... I do it
    the other way around: never use typedefs, and always use struct tags.
    I won't claim this is the dominant style, but I'm not alone, based on
    earlier discussions here.

    One reason I dislike typedefed structs is that (as far as I can tell)
    you cannot forward-declare them.

    Jorgen Grahn, Feb 5, 2014
  17. fl

    James Kuyper Guest

    On 02/05/2014 12:47 PM, Jorgen Grahn wrote:
    typedef struct tag name;

    name *pname;

    struct tag{
    int i;
    double d;

    name object;

    That last line would be a constraint violation if moved before the
    struct tag definition.
    James Kuyper, Feb 5, 2014
  18. Yes, but you can do that only if you use struct tags as well as
    typedefs. (I'm not saying that's a bad idea, but it's inconsistent with
    what BartC said upthread about avoiding struct tags.)
    Keith Thompson, Feb 5, 2014
  19. fl

    James Kuyper Guest

    Sorry - I missed that aspect of what Jorgen was saying. He's right -
    typedefs of tagless structs cannot be forward declared.
    James Kuyper, Feb 5, 2014
  20. fl

    Jorgen Grahn Guest

    For once I would have been happy to be proven wrong ...

    What I often want to do in practice is to deal with 'struct foo*'
    from some library, without having to pull in the library's header file.
    I like every translation unit to know as little as possible -- see as
    few names as possible.

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