简体   繁体   中英

Why is “typedef struct foo foo;” considered harmful?

In typedef and struct namespaces in C vs C++ , one of the comments seems to imply that exposing some struct foo is preferable to using typedef along the lines of...

typedef struct foo foo;

...and then using foo instead of struct foo throughout the API.

Are there any downsides to the latter variant?

The only downside(*) is that it hides the fact that foo is a struct, and not an alias for some builtin type.

Note(*): it's matter of taste whether this is a downside for you.

  • It's good for total opaqueness (see the first comment below).
  • To see why some people think this is a downside, check the linux kernel coding style (typedefs chapter).

It depends how much you like the word struct . If you feel your program will be made clearer by a liberal sprinkling of struct that and struct tother (you can't have struct this in C++, of course), then by all means use the struct version.

Personally, I don't think that repeating struct provides any benefit and I'm happy to use just the typedef name. And because C++ effectively provides the typedef struct xyz xyz; declaration automatically (it isn't quite accurate, not least because you can explicitly write that in C++, but it is close enough that you probably don't have to worry about it), I think it makes perfect sense to use the same in C. The C compiler is happy with it, so I normally use typedef struct tag tag; and then use tag and tag * where needed.


For an alternative but wholly tenable view, read the Linux kernel coding style guide.


Note that C2011 allows you to redefine a typedef as long as it aliases the same type:

ISO/IEC 9899:2011 §6.7 Declarations

Semantics

¶5 A declaration specifies the interpretation and attributes of a set of identifiers. A definition of an identifier is a declaration for that identifier that:

— for an object, causes storage to be reserved for that object;

— for a function, includes the function body; 119)

— for an enumeration constant, is the (only) declaration of the identifier;

— for a typedef name, is the first (or only) declaration of the identifier.

Contrast with C99 where this was not possible:

ISO/IEC 9899:1999 §6.7 Declarations

Semantics

¶5 A declaration specifies the interpretation and attributes of a set of identifiers. A definition of an identifier is a declaration for that identifier that:

— for an object, causes storage to be reserved for that object;

— for a function, includes the function body; 98)

— for an enumeration constant or typedef name, is the (only) declaration of the identifier.

This simplifies the creation of type definitions as long as you're consistent (but only if you have a sufficiently compatible C2011 compiler on each platform of relevance to you).

On whether or not to typedef structure types:

Here is some opinions around (all against typedefing structures):

From OpenBSD style guide:

"Avoid using typedefs for structure types. This makes it impossible for applications to use pointers to such a structure opaquely, which is both possible and beneficial when using an ordinary struct tag."

From Linux kernel coding style:

"It's a mistake to use typedef for structures and pointers."

From Expert C Programming by Peter Van der Linden:

"Don't bother with typedefs for structs. All they do is save you writing the word "struct", which is a clue that you probably shouldn't be hiding anyway."

It's more or less a matter of taste.

By just declaring a struct tag, the name is also available to be used for variables, functions, or enumerators in the same scope (or even another type, if you enjoy confusion); and users must write the word struct , which makes their code more explicit.

By also declaring a type name, you allow people not to type struct if they don't want to.

My comment in the other question was referring to the declaration of a pointer type with the same name as the struct tag:

typedef struct foo * foo;

Stylistically, this is slightly unpleasant because it hides the fact that it's a pointer. This hides the fact that it is a pointer; that is perhaps fine in the context of that question, where this is an opaque type defined by an API, but in my opinion would be rather rude for a non-opaque type. It also breaks compatibility with C++. In that language, such a declaration is invalid, since struct foo introduces foo into the current namespace rather than a separate tag space, and prevents the declaration of any other type with the same name in that namespace.

Just stick to a naming convention and you'll be fine.

typedef struct
{
  //...
}              t_mytype;
//...
t_mytype thing;

This way you'll know it's a custom type. As for it being a struct, just use explicit names and not really t_mytype

One another argument against typedef is the difficulty it write clean headers. Let's see an example of header:

#ifndef HEADER_H
#define HEADER_H
#include "s.h"
void f(struct s *);
#endif

This header can be improved. Indeed, struct s does not need to be defined. So it could be written:

#ifndef HEADER_H
#define HEADER_H
struct s;
void f(struct s *);
#endif

Thus, the user may use struct s as an opaque struct and we can keep "sh" private.

Let's do the same thing but with typedef :

#ifndef HEADER_H
#define HEADER_H
typedef struct s s_t;
void f(s_t *);
#endif

The line typedef struct s s_t will appears in every header that want to use s_t * and I dislike redundant code. There are multiple ways to avoid that, but the easiest is probably to get rid of typedef.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM