Typedef structs

C

CBFalconer

Tim said:
.... snip ...

Let me suggest this rule: Always use typedefs for structs, except in
cases where the advantages of not using them outweigh the advantages
of using them. I've yet to see a statement in this thread about what
the advantages of not using typedefs for structs are, let alone a
comparison of the different advantages for the two approaches.

I think the general feeling is not to hide the fact that an entity
is a struct, and that use implies selecting fields. Of coarse
this doesn't apply when you want to export an anonymous structure
and provide routines for operating on its fields. In that case a
typedef is probably the preferred method.
 
K

Keith Thompson

Tim Rentsch said:
^^^^^^^^^
What reasons would you offer that it shouldn't be hidden? In a separate
article I responded to another poster's query and listed some advantages
of the separate type name approach. Could one of the just-use-structs
advocates respond and list some principal advantages of not using
a separate type name?

I'm probably not one of the "just-use-structs advocates", but I'll
respond anyway.

I certainly have no objection to abstract types, and they should
probably be used more often than they are, but not all types are
abstract.

I gave several examples in my previous post. To repeat one of them,
the type "struct tm", declared in <time.h>, is visibly a struct.
Declaring a typedef, say "typedef struct tm { ... } tm;", and
declaring an object as
tm obj;
rather than as
struct tm obj;
doesn't really hide anything when you're referring to "obj.tm_sec"
anyway.

If struct tm were an abstract data type, with no defined members and a
purely functional interface, the typedef would make perfect sense.

Personally, I see the debate as something similar to the controversies
over brace style. Most people have their own preferences, and many
people feel quite strongly about them (perhaps with good reason), but
we all had better be able to cope with code written in styles other
than the one we like.

[...]
Keith, I'm disappointed. This kind of rhetoric - a content-free
statement giving a "non-argument" argument, including the emotional
hook word "gratuitous" - should be below you.

Huh?

The statement in parentheses wasn't meant to be an argument, just a
disclaimer. Feel free to read "gratuitous" as "not strictly
necessary" if it will make you happy. (I don't see "gratuitous" as a
purely pejorative term.)
 
M

Michael Wojcik

Ahh, this is a good question.

Indeed, it is *the* question, since you were responding to Chris'
recommendation against typedef'ing structs, and since - contrary
to your blithe (a less charitable reader might call it arrogant)
assumption in another post that they should be obvious to any
experienced C programmer - your justifications for the practice
are neither obvious nor obviously true.
I would offer several reasons:

1. (minor) Slight economy of expression - shorter to omit 'struct'.

Economy of expression is not an absolute good. In fact, it's
arguably done significant damage to software on the whole, due to
the proliferation of code that's difficult to maintain due to
unnecessary terseness.

Moreover, it discards information, which makes the code harder to
understand, which is another obstacle to maintenance. Hiding
information in source code is only good when abstraction is
merited; and in such cases, it's redundant to uphold information-
hiding in itself as an advantage.
2. Using a typedef'ed name gives greater flexibility in the choice
of type - if later we want some_type_name to be a 'union' or 'int'
or 'enum', less of the program will need to change as a result.

Very little less, in most cases. When I write code that operates
on a struct, and that struct subsequently becomes a union or an
int or an enum, chances are excellent that the code itself will
have to change. If I am not hiding the type's category behind a
typedef, the implementation will helpfully notify me if I should
neglect to make such changes. If I am, there are plausible
situations where it will not.
3. Greater safety - if the type is defined in a header file (as it
very likely may be), and the header file is not #include'ed, using

some_type_name *x;

will produce an error, whereas

struct some_type_name_struct_tag *x;

need no produce any diagnostic at all. Sometimes the second case is
perfectly easy to figure out, but the first case is *always* easy to
figure out.

This strikes me as far less common than the previous case. If
the type is defined in a header file, then code which should be
including that header probably needs it for other reasons (eg to
supply prototypes for the API associated with the abstract data
type you're hypothesizing - what else are you going to do with a
pointer to an incomplete type, than pass it to some function
which understands it?).

Further, since all struct pointers have the same alignment and
representation, and since your example is only meaningful when
"struct some_type_name_struct_tag" is an incomplete type, I don't see
what damage is done in the case where the translation unit
accidentally declares its own "struct some_type_name_struct_tag *x".
In fact, unless I am mistake, the only effect of such a declaration
is to place "some_type_name_struct_tag" into the struct tag namespace
and to declare a variable x which can be used semantically to hold any
struct's address (syntactic constraints notwithstanding).
4. Natural extension to opaque types

Opaque data types is one of only two cases where I can see any
advantage to typedef'ing structs. (The other is for passing to
va_arg, which is not compatible with the full C type syntax and so
sometimes requires "helper" typedefs.)

Even in the case of opaque data types, however, there are times when
the struct tag is more useful, I would argue. I like to apply some
fairly strict rules for coupling and information sharing among the
modules (translation units) of many of my projects. In many cases
some use pointers to types that are incomplete to them but complete
for other modules. In this case there's no benefit to hiding the
type category; both opaque and completed types are available to all
the developers who might maintain the code.
 
M

Michael Wojcik

What reasons would you offer that it shouldn't be hidden?

I've provided one already in another post: it gives the
implementation more power to catch errors if the type category
should change (an example you raised as an advantage of hiding
the category). Frankly, I think the fact that using the struct
tag provides even a small amount of additional information to
maintenance programmers is in itself a significant advantage.
More importantly, information hiding.

Which differs from data abstraction how, in this case?
See the well-known papers
by David Parnas. Also Brooks's "Mythical Man Month", 20th Anniversary
Edition.

Don't you think that's a bit weak as an appeal to authority? See
*what* in Parnas or Brooks?
Let me suggest this rule: Always use typedefs for structs, except in
cases where the advantages of not using them outweigh the advantages
of using them.

Sure. Here's mine: Never use typedefs for structs, except in cases
where the advantages of using them outweigh the advantages of not
using them.
Keith, I'm disappointed. This kind of rhetoric - a content-free
statement giving a "non-argument" argument, including the emotional
hook word "gratuitous" - should be below you.

Is English not your first language? "gratuitous" has a well-
defined denotation, and while it may be an "emotional hook word"
for you, it's quite meaningful for many of us. And I'm puzzled
that you consider this statement an "argument" at all on Keith's
part, since it's clearly parenthetical (even without the
parentheses) and explicitly expresses an opinion.

And it's an opinion *in support of your side*.

And *all* argumentation is rhetoric. Perhaps you should consult
a dictionary on the denotation of that term, too.

And if you're going to get your feathers ruffled by imagined
slights like that, I don't see you lasting too long here, where
regulars are likely to defend their opinions vigorously.

And, finally, with the single exception of use with va_arg, I am
unable to think of a use of typedef which is not gratuitous. Can
you provide an example?

--
Michael Wojcik (e-mail address removed)

This is a "rubbering action game," a 2D platformer where you control a
girl equipped with an elastic rope with a fishing hook at the end.
-- review of _Umihara Kawase Shun_ for the Sony Playstation
 
C

Chris Torek

Opaque data types is one of only two cases where I can see any
advantage to typedef'ing structs. (The other is for passing to
va_arg, which is not compatible with the full C type syntax and so
sometimes requires "helper" typedefs.)

Indeed, these are the two primary "pro-typedef" cases for me, as
well. (Of course, va_arg really does *require* typedefs at times,
as you note.)

There is another "pro-typedef" case not involving structures,
having to do with naming. Abstraction and naming seem to me to
go hand-in-hand, and one way to make something difficult become
comprehensible is to name it. The sloganeering might go: "Name
it to tame it." :)

I think it can be argued (but I do not have time to pursue this
right now) that this "naming argument" actually covers the opaque
data type situation. In languages other than C, where "bare" type
declarations are (or can be) type-creating operations (e.g., Ada
has both "sub-typing" and "separate-typing"), such abstractions
with their names may cover any type. C is a bit peculiar in that
to create a *new* type, we have to use struct (or union or enum,
but struct is the general version). To make a new datatype that
contains only an integer, we have to create a whole structure:

struct T1 { int value; };
struct T2 { int value; };

Now types T1 and T2 are different, even though they both just have
a single "int" element named value. You cannot mix up the types
without getting a compiler diagnostic.

Until C99, it was impossible in general (in "full generality" at
least) to hide the fact that some typedef'ed alias actually covered
a structure. Consider:

typedef
#include "secret.h"
alias_t;

where "secret.h" contains some valid token sequence that results
in making "alias_t" an alias for some data type, possibly a struct
(or union or enum) but perhaps a scalar or pointer.

Now suppose we see this:

#include "secret2.h" /* defines SOME_CONSTANT of type alias_t */

void somefunc(alias_t);

void f(void) {
somefunc(SOME_CONSTANT);
}

This immediately tells us, in C89, that alias_t is *not* a struct.
There is no way to pass an actual constant of some "struct" type.
(Admittedly, one can "cheat" -- secret2.h might have "const struct
tag FAKE_CONSTANT = { ... };" and then #define SOME_CONSTANT to
expand to FAKE_CONSTANT. This *almost* completely hides it --
#ifdef works right for instance -- except that we can now compute
&SOME_CONSTANT.)

C99 fixes this by adding anonymous aggregates:

#define SOME_CONSTANT ((const struct tag){ ... })

In practice, in a lot of real code one sees:

typedef /* not-very-secret stuff */ alias_t;
...
void somefunc(alias_t);
void f(void) {
somefunc(32.4); /* exposed! alias_t is some floating-pt type */
}

so that the abstractions are "leaky".

Given leaky abstractions, and C's syntax, I prefer to just spell
out the "struct" keyword, most of the time.
 
K

Keith Thompson

Opaque data types is one of only two cases where I can see any
advantage to typedef'ing structs. (The other is for passing to
va_arg, which is not compatible with the full C type syntax and so
sometimes requires "helper" typedefs.)

Sometimes it does, but not in the case of a simple "struct foo" type
name.

The requirement for the type argument to va_arg is (C99 7.15.1.1,
underscores denoting italics):

The parameter _type_ shall be a type name specified such that the
type of a pointer to an object that has the specified type can be
obtained simply by postfixing a * to _type_.

C90 has identical wording.

The type of a pointer to "struct foo" is just "struct foo *"; there's
no need for a typedef.
 
M

Michael Wojcik

Sometimes it does, but not in the case of a simple "struct foo" type
name.

Right. I meant to write that I thought typedef's in general were
only useful for creating opaque data types and for passing complex
types to va_arg; the reference to typedef'ing structs in particular
came from an earlier edit. Thanks for supplying the clarification.

I don't believe I've actually ever passed a sufficently-complex type
to a variadic function to need a typedef, in fact.

--
Michael Wojcik (e-mail address removed)

You have Sun saying, "Who needs Linux? We have Solaris." You have
Microsoft saying, "Who needs Linux? We have Windows 2000." Then you
have IBM saying, "I think we all need Linux." Only the greatest
sinners know how to really repent. -- John Patrick, IBM VP
 
D

Dave Thompson

file1.c
-------

typedef struct my_structure1_tag {

// FOO;

} my_structure1;

file2.c
-------

typedef struct my_structure2_tag {

my_structure1 *my_struct;

} my_structure2;

Now, in order to get file2.c to compile I have to change it so that it
reads:

typedef struct my_structure2_tag {

STRUCT my_structure1 *my_struct;

} my_structure2;

Without the STRUCT i would get a syntax error because the compiler has
not compiled file1.c <snip>

Right. But when/if you do get that declaration, it's of struct
my_structure1_tag, not struct my_structure1.Those are different, which
is why your compiler diagnoses the type as incompatible.

One convenient way to fix this is to use the same name for the struct
(or union) tag and the typedef. This *is* legal; they are in separate
namespaces. <OT> In C++ this is effectively done for you; the tag is
by default a typename so </> if you want to use the same practices,
and maybe even some of the same code, in these two related but
different languages this is an easy one to make compatible.

- David.Thompson1 at worldnet.att.net
 
S

Steve Lambert

Could someone explain why you need the struct keyword at all when declaring
a variable :

The code below works ok and I've declared my_struct without using the struct
keyword.

#include <stdio.h>
struct test_struct
{
int a;
int b;
};
void main()
{
test_struct my_struct;

printf("hello world\n");
}
 
A

Al Bowers

Steve said:
Could someone explain why you need the struct keyword at all when declaring
a variable :

You need it because the Standard for the C Language, ISO/IEC 9899:1999,
requires it.

The code below works ok and I've declared my_struct without using the struct
keyword.

My guess is that you are compiling with C++ Compiler. I believe
the keyword is not needed in C++ and function main returns type
void. In C, the keyword is required and function main returns type
int. The C Language is defined by the Standard that I mentioned above
and not by your compiler.
 
K

Keith Thompson

Al Bowers said:
My guess is that you are compiling with C++ Compiler. I believe
the keyword is not needed in C++ and function main returns type
void. In C, the keyword is required and function main returns type
int. The C Language is defined by the Standard that I mentioned above
and not by your compiler.

main returns int in both C and C++. (C++ is actually more strict than
C; both allow implementation-defined declarations of main, but only C
those implementation-defined declarations to have a return type other
than int.)
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top