为了在C中定义新的数据类型,例如链表的类型,可以使用以下定义之一
struct list_node {
int x;
struct list_node * next;
};
//1
typedef struct list_node list1;
//2
typedef struct list_node *list2;
从我所看到的,通常的做法是第一个定义。
问题是第二个定义是否也是可以接受的做法。 在哪种情况下,如果有人应该比第一个更喜欢第二个? 前提是我们使用的变量是struct list_node的指针 是否可以对两种类型进行相同的操作? 第一个有什么好处?
答案 0 :(得分:5)
我要求API用户键入“*”,即typedef结构,而不是指向结构的指针。这是GLib中广泛使用的样式,它是更受欢迎的C栈之一。
它很好用,因为 很重要,知道你是否有指向结构或结构本身的指针。例如,您可以在类型的变量中存储NULL吗?如果隐藏对象是指针,则必须创建特殊的NIL_NODE或其他值来替换NULL。如果你只是把它作为一个指针,那么人们可以像对待它那样对待它。
另一个重要的好处是能够将实际的struct定义放在私有的地方,即在.c文件而不是在头文件中。您只需将typedef放在标头中,同时保持结构本身对API用户不透明。这要求人们只使用您提供的导出方法来操作结构。这也意味着如果更改结构字段,则不必重建世界。
采用这种方法的另一个原因是,有时你确实想要一个可以复制的结构,你仍然想要输入它。拿一个像GdkPoint这样的东西:
typedef struct {
int x, y;
} GdkPoint;
这里允许直接进行struct访问很有用,例如:
GdkPoint point = { 10, 10 };
GdkPoint copy = point;
do_stuff_with_point(©);
但是,如果您的约定是“GdkPoint”typedef将是一个指针,那么您将不得不一致。
如果您可以告诉什么是指针和什么不是,那么代码就更清楚了,如果您不在头文件中放置结构定义,代码会更好地封装(对于表示抽象,不透明数据类型的结构,这可能是最常见的一种)。
C数据类型的默认模板在标题中是这样的:
typedef struct MyType MyType;
MyType* my_type_new(void);
void my_type_unref(MyType *t);
void my_type_ref(MyType *t);
然后是.c文件中的实际“struct MyType”,以及该类型的new,unref和任何操作。
例外的是Point,Rectangle,Color等类型,它是“普通旧数据”并且需要直接字段访问;如果您不需要引用计数,则另一种变体是使用my_type_free()而不是_unref()。
无论如何,这是一种风格,基本上是GLib风格,它被广泛使用并且已知效果很好。
答案 1 :(得分:1)
我更喜欢第一种风格,因此很清楚哪些类型是对象,哪些类型是指针。但我发现C指针很容易理解/解释,显然很多人都没有。因此,如果您认为阅读代码库的大多数人都不会理解指针,请在任何地方使用typedef STRUCT_FOO *PSTRUCT_FOO
,就像Win32 API一样。
答案 2 :(得分:0)
考虑使用以下两种方法:
typedef struct list_node Node;
typedef Node* ListHead;
答案 3 :(得分:0)
只要标识符清楚它是一个指针然后没有坏处(我个人更喜欢后缀ala _Pointer或_Ptr,但任何适合项目)。也就是说,对于纯C代码,避免显式*
没有实际好处。对于混合C / C ++环境或纯C ++,我经常看到typedef
指针用于指向合理化/合理化的指针,以便于转换,使用和切换智能指针类型。这可能有些道理,但我从未发现自己想要采用这种做法。
答案 4 :(得分:0)
typedef int * ptr_int; ptr_int x,y,z;
程序员可能会感到困惑的是,所有三个x,y,z都是int *类型,即 指向int。 但在Reality中,只有x是int *类型y,z是简单的int。
因为ptr_int x,y,z;等于int * x,y,z; 不是int * x,* y,* z;
所以, typedef也会给程序员带来困惑,并可能导致错误和错误。