typedef 向前声明_C语言结构的typedef与前向声明

I was using typedef for structures everywhere in my application. I then started to refactor into several

header files when it started to get clunky. I noticed I needed to forward declare Object, and Klass.

Well, to my surprise, I couldn't forward declare Object, or Klass. This is because, as you can see in the

Object and Klass structure, I'm using a typedef of Object and Klass.

//Klass.h

typedef struct Klass Klass_t;

struct Klass

{

void (*_initialize)(Object_t* object, Klass_t* klass);

};

//Object.h

typedef struct Object Object_t;

struct Object

{

Klass_t* _klass;

};

At first, using typedef was great. But trying to forward declare Object:

struct Object_t;

Doesn't work as I would need to rewrite by function declarations as:

void (*_initialize)(struct Object_t* object, Klass_t* klass);

So I decided to just typedef Object inside the Klass.h header file:

typedef struct Object Object_t;

Well when all header files are included into my Main.c file, it complians:

Object.h:5: error: redefinition of typedef 'Object_t'

So, I then decided to just drop all struct typedefs and explicity declare my structures.

Is there a way to typedef a structure and forward declare in another file without explicitly using struct Object?

I want to keep structure typedefs inside the header file where

the structure is declared. If I have to group all typedefs inside one header file then I would rather not use typedef at all. Anyways, thanks for your time.

解决方案

Remember that a typedef is just an alternative name for a type. There's a reason the Linux kernel doesn't use typedefs for structure types, and you're demonstrating it.

There are a couple of ways around your problem. I note that C11 does allow multiple occurrences of the same typedef, but I'm assuming you're stuck with an older compiler that does not support that.

TL;DR

Even though the Linux kernel doesn't use typedefs, I usually do use typedefs, but I mostly avoid mutually referential structure types (I can't think of any code where I used such a type). And, like Jens Gustedt notes in his answer, I almost invariably use the notations:

typedef struct SomeTag SomeTag;

so that the type name and the structure tag are the same (they're in different namespaces). This operation is not necessary in C++; when you define struct SomeTag or class SomeTag, the name SomeTag becomes a type name without the need for an explicit typedef (though a typedef does no harm other than revealing that the author is more experienced in C than C++, or the code originated as C code).

I also observe that names starting with an underscore are best treated as 'reserved for the implementation'. The rules are a little more complex than that, but you run a risk of the implementation usurping your names — and being within its rights to usurp your names — when you use names starting with an underscore, so don't. Likewise, POSIX reserves type names ending _t for the implementation if you include any POSIX headers (such as when you aren't compiling in strict Standard C only mode). Avoid creating such names; they'll hurt you sooner or later. (I've not fixed the code below to deal with either of these issues: caveat emptor!).

In the code fragments below, I'm mostly ignoring the code that prevents multiple inclusions (but you should have it in your code).

Extra header

typedefs.h:

typedef struct Object Object_t;

typedef struct Klass Klass_t;

klass.h

#include "typedefs.h"

struct Klass

{

void (*_initialize)(Object_t *object, Klass_t *klass);

};

object.h

#include "typedefs.h"

struct Object

{

Klass_t *_klass;

};

This works because the two type names Klass_t and Object_t are declared before they're used.

Use struct Object in prototype

klass.h

typedef struct Klass Klass_t;

struct Object;

struct Klass

{

void (*_initialize)(struct Object *object, Klass_t *klass);

};

Or, for consistency, it might even use:

void (*_initialize)(struct Object *object, struct Klass *klass);

object.h

#include "klass.h"

struct Object

{

Klass_t *_klass;

};

This works because (within broad limits — basically, if the types are defined at file scope, not inside a function) struct Object always refers to the same type, regardless of whether all the details are fully defined yet.

GCC 4.8.2

Under all of -std=c89, -std=c99 and -std=c11, GCC 4.8.2 accepts replicated typedefs, as in the code below. It requires -std=c89 -pedantic or -std=c99 -pedantic to get errors about the repeated typedefs.

Even without the -pedantic option, GCC 4.5.2 rejects this code; however, GCC 4.6.0 and later versions accept it without the -pedantic option.

klass.h

#ifndef KLASS_H_INCLUDED

#define KLASS_H_INCLUDED

typedef struct Klass Klass_t;

typedef struct Object Object_t;

struct Klass

{

void (*_initialize)(Object_t *object, Klass_t *klass);

};

#endif /* KLASS_H_INCLUDED */

object.h

#ifndef OBJECT_H_INCLUDED

#define OBJECT_H_INCLUDED

typedef struct Klass Klass_t;

typedef struct Object Object_t;

struct Object

{

Klass_t *klass;

};

#endif /* OBJECT_H_INCLUDED */

consumer.c

#include "klass.h"

#include "object.h"

Klass_t k;

Object_t o;

You'll have to decide whether that's a risk you're willing to take for your code — how important is portability, and to which versions of C (and which C compilers) must it be portable.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值