【问题标题】:use pointer to struct or not when using typedef in C [duplicate]在C中使用typedef时是否使用指向结构的指针[重复]
【发布时间】:2011-07-03 04:50:45
【问题描述】:

为了在 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 的指针 是否可以对两种类型进行相同的操作? 第一种有什么好处?

【问题讨论】:

标签: c list pointers struct typedef


【解决方案1】:

我会要求 API 用户键入“*”,即 typedef 结构,而不是指向结构的指针。这是 GLib 中广泛使用的样式,它是最流行的 C 堆栈之一。

效果很好,因为知道您是否拥有指向结构或结构本身的指针很重要。例如,您可以将 NULL 存储在类型的变量中吗?如果你隐藏一个对象是一个指针,你必须创建一个特殊的 NIL_NODE 或其他值来替换 NULL。如果你只是把它作为一个指针,那么人们可以把它当作一个指针来对待。

另一个重要的好处是能够将实际的结构定义放在私有的地方,即在 .c 文件中而不是在头文件中。您可以只将 typedef 放在标头中,同时保持结构本身对 API 用户不透明。这要求人们仅使用您提供的导出方法来操作结构。这也意味着如果您更改结构字段,您不必重建世界。

选择这条路的另一个原因是,有时你确实想要一个可以复制的结构,但你仍然想对它进行 typedef。拿一个像 GdkPoint 这样的东西:

  typedef struct {
     int x, y;
  } GdkPoint;

这里允许直接访问结构体很有用,例如:

 GdkPoint point = { 10, 10 };
 GdkPoint copy = point;
 do_stuff_with_point(&copy);

但是,如果您的约定是“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 和对该类型的任何操作。

点、矩形、颜色等类型是“普通旧数据”并且需要直接字段访问的类型除外;如果不需要引用计数,另一种变化是使用 my_type_free() 而不是 _unref()。

无论如何,这是一种风格,基本上是 GLib 风格,它被广泛使用并且众所周知。

【讨论】:

  • 我完全同意。使用typedef 隐藏类型是指针还是结构通常不是一个好主意(除非您将不透明指针用于库接口)。老实说,我通常更喜欢将 struct 称为 struct 并完全避免使用 typedef,但如果您要使用 typedef 某些东西,请将其设为结构而不是指针。
  • glib 样式将 CamelCase 用于结构 typedef,小写用于原始类型 typedef,因此无需键入“struct”,同时保持清晰。还保留了在标题中没有不透明结构的能力
【解决方案2】:

我更喜欢第一种风格,所以很清楚哪些类型是对象,哪些类型是指针。但我发现 C 指针易于理解/解释,(显然)很多人不理解。因此,如果您认为大多数阅读您的代码库的人不会理解指针,请在任何地方使用 typedef STRUCT_FOO *PSTRUCT_FOO,就像 Win32 API 一样。

【讨论】:

    【解决方案3】:

    考虑同时使用这两种方法:

    typedef struct list_node Node;
    typedef Node* ListHead;
    

    【讨论】:

      【解决方案4】:

      只要标识符清楚地表明它是一个指针,那么就没有什么坏处(我个人更喜欢后缀ala _Pointer 或_Ptr,但只要适合项目)。也就是说,对于纯 C 代码,避免显式 * 没有实际好处。对于混合 C/C++ 环境或纯 C++,我经常看到使用 typedefs 来合理化/合理化指针以促进智能指针类型的转换、使用和切换。这可能有些道理,尽管我从未发现自己想采用这种做法。

      【讨论】:

        【解决方案5】:

        typedef int* ptr_int; ptr_int x,y,z;

        程序员可能会感到困惑,所有三个 x、y、z 都是 int* 类型,即 指向 int 的指针。 但在现实中,只有 x 是 int* 类型 y 而 z 是简单的 int。

        因为 ptr_int x, y, z;等于 int* x, y, z; 不是 int*x, *y, *z;

        所以, typedef 还会在程序员心中造成混乱,并可能导致错误和错误。

        【讨论】:

          猜你喜欢
          • 2018-11-03
          • 1970-01-01
          • 2010-12-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-25
          • 2020-03-21
          • 2022-07-22
          相关资源
          最近更新 更多