虽然我很少编写 C 代码,但我经常看到它(主要是因为我所在领域的书籍将其作为算法示例的参考语言),并且关于变量/参数的声明方式的问题已经困扰我一段时间了。最好的例子是这个带有扭曲示例的列表,关于 Linux 内核中使用的链接列表的特定实现(抱歉,我最初有一个博客文章的链接,但显然该博客文章已被删除,我从我的浏览器缓存)。
struct blog {
...
struct ls posts;
};
struct post {
...
struct ls blog_posts;
};
void delete_blog(struct blog *blog) {
...
struct post *p;
ls_for_each(&blog->posts, p, blog_posts) {
free(p);
}
free(blog);
}
令我烦恼的是他们到处重复关键字 struct。我的意思是像 ls、blog、post 这样的东西被声明为结构体,那么每次声明该类型的变量或函数参数时都说它是结构体有什么意义呢?这告诉编译器它无法从您实例化的东西已被定义为结构这一事实中推断出什么?
在 C 语言中,如果你有:
struct thing {
// stuff here
};
并且您想要拥有该类型的变量,您需要:
使用
struct thing
typedef struct thing thing_t;
thing_t
作为类型说明符。
struct
标签与通常的标识符位于不同的命名空间中。因此需要使用
struct
关键字来指定这一点。一个著名的例子是 POSIX,其中有一个 struct stat
和一个函数 stat
。C 是一种相当古老的语言,它特意创建了一种语法来区分可以直接由机器指令表示的类型和更复杂且跨越多个内存位置的类型。
“Typedef”被添加到语言中,以允许创建不包含结构的较短名称,但是使用完整的结构语法 - 特别是在历史上下文中使用,其中系统结构的原始定义定义为“struct”没有相应的 typedef 缩写形式。
与 C++ 相比,C++ 是一种较晚出现的语言,它允许仅通过类/结构名称来引用类/结构,无论它是否是使用 typedef 定义的。
随着问题的推移,答案是,事情就是这样,因为它是......
编辑:只要看看你的示例代码,有一个值得注意的情况,结构体向编译器行为添加了一些东西——在大多数情况下,必须先定义一个类型,然后才能在另一个声明中使用它——除了当您引用了 struct sometype*
(即指向结构的指针),在这种情况下,编译器很乐意在使用后定义
sometype
。所以
struct post {
struct post *nextpost;
struct post *prevpost;
...
};
成为可能,因为
post
直到结构体的右括号才被定义。
如果函数接受参数(/参数),则必须声明该参数的类型。 如果你不能使用 struct 这个词,你怎么能声明该参数是一个结构体呢?
typedef
改造它们的
struct
并使用一些命名约定。例如 gtk/gtkalignment.h
有:
typedef struct _GtkAlignment GtkAlignment;
typedef struct _GtkAlignmentPrivate GtkAlignmentPrivate;
typedef struct _GtkAlignmentClass GtkAlignmentClass;
我自己的习惯是命名
foo_st
struct
和 foo_t
类型,所以我经常编码typedef struct foo_st foo_t;
如果它是
union foo_un
,我会使用
union
。