我以前看过C结构以几种不同的方式声明。为什么会这样,如果有什么,每个都有什么不同?
例如:
struct foo {
short a;
int b;
float c;
};
typedef struct {
short d;
int e;
float f;
} bar;
typedef struct _baz {
short a;
int b;
float c;
} baz;
int main (int argc, char const *argv[])
{
struct foo a;
bar b;
baz c;
return 0;
}
答案 0 :(得分:34)
嗯,明显的区别在你的main
:
struct foo a;
bar b;
baz c;
第一个声明属于非typedef
ed struct
,需要使用struct
关键字。第二个是typedef
匿名struct
,因此我们使用typedef
名称。第三个结合了第一个和第二个:您的示例使用baz
(这很方便),但可以轻松地使用struct _baz
来达到同样的效果。
更新:larsmans' answer提到了一个更常见的情况,您必须至少使用struct x { }
来制作链接列表。第二种情况在这里是不可能的(除非你放弃理智并改为使用void *
)因为struct
是匿名的,typedef
直到{{1}才会发生已定义,无法创建指向struct
类型本身的(类型安全)指针。第一个版本适用于此用途,但第三个版本在我的经验中通常是首选。给他一些代表。
更明显的区别在于命名空间放置。在C中,struct
标记放在与其他名称不同的名称空间中,但struct
名称不是。所以以下是合法的:
typedef
但以下情况并非如此,因为名称struct test {
// contents
};
struct test *test() {
// contents
}
的含义不明确:
test
typedef struct {
// contents
} test;
test *test() {
// contents
}
使名称更短(总是加号),但它将它与变量和函数放在同一名称空间中。通常这不是问题,但除了简单的缩短之外,它是一个微妙的差异。
答案 1 :(得分:28)
这主要取决于个人偏好。我想给新类型一个以大写字母开头的名称并省略struct
,所以我通常会写typedef struct { ... } Foo
。这意味着我不能写struct Foo
。
例外情况是struct
包含指向其自身类型的指针,例如
typedef struct Node {
// ...
struct Node *next;
} Node;
在这种情况下,您还需要声明struct Node
类型,因为typedef
不在struct
定义范围内。请注意,两个名称可能相同(我不确定下划线约定的来源,但我猜旧的C编译器无法处理typedef struct X X;
)。
答案 2 :(得分:7)
您的所有用法在语法上都是正确的。我更喜欢以下用法
/* forward declare all structs and typedefs */
typedef struct foo foo;
.
.
/* declare the struct itself */
struct foo {
short a;
int b;
foo* next;
};
观察到这很容易允许使用typedef
本身声明中的struct
,甚至是struct
相互引用的{{1}}。
答案 3 :(得分:5)
之所以产生混淆,是因为有些声明实际上声明了三个C结构。你需要记住以下两者之间的区别: 1.一个typedef声明, 2.结构定义,和 3.结构声明。
它们都是非常不同的C结构。他们都做不同的事情;但如果你愿意,你可以将它们组合成一个复合构造。
让我们依次看看每个声明。
//================================================
struct foo {
short a;
int b;
float c;
};
这里我们使用最基本的结构定义语法。我们将foo定义为C 类型,以后可以使用以下语法来声明该类型的变量:
foo myFoo; // Declare a struct variable of type foo.
// ============================================= ======= 下一个声明有点像前面的语法,因为它声明了C类型,但它使用了typedef语法。让我们使用之前的基本声明将其分解为其组件。
typedef foo bar; // Declare bar as a variable type, the alias of foo.
bar myBar; // This is ssemantically the same as: foo myBar;
现在只需用之前的语法替换“foo”,瞧!
typedef struct {
short d;
int e;
float f;
} bar;
//==================================================================
typedef struct _baz {
short a;
int b;
float c;
} baz;
以上语法等同于以下声明序列。
struct _baz {
short a;
int b;
float c;
}
typedef _baz baz; // Declare baz as an alias for _baz.
baz myBaz; // Is the same as: _baz myBaz;
//========================================================