typedef的指针类型被认为是不好的做法吗?

时间:2010-09-23 19:39:31

标签: c pointers typedef

  

可能重复:
  Typedef pointers a good idea?

我在许多使用过的API中都看到了这种奇怪之处:<​​/ p>

typedef type_t *TYPE;

我的观点是,声明TYPE类型的变量不会说明事实上已经声明了一个指针。

你和我一样认为这会带来很多困惑吗?这是否意味着强制执行封装,还是有其他原因?你认为这是一种不好的做法吗?

8 个答案:

答案 0 :(得分:23)

一般来说,这是一种不好的做法。重要的问题是它与const

的效果不佳
typedef type_t *TYPE;
extern void set_type(TYPE t);

void foo(const TYPE mytype) {
  set_type(mytype);  // Error expected, but in fact compiles
}

为了让foo()的作者表达他们的真实含义,提供TYPE的图书馆还必须提供CONST_TYPE

typedef const type_t *CONST_TYPE;

以便foo()可以拥有签名void foo(CONST_TYPE mytype),此时我们已经陷入了闹剧。

因此有一条经验法则:

  

创建结构的typedef(特别是不完整的结构),而不是那些结构的指针。

如果底层结构的定义不是公开可用的(这通常是值得称赞的),那么该封装应该由结构提供不完整,而不是由不方便的typedef提供:

struct type_t;
typedef struct type_t type_t;

void set_type(type_t *);
int get_type_field(const type_t *);

答案 1 :(得分:6)

一个常见的习语是用_p为类型后缀,表示它是一个指针,同时仍然保留了指针质量。

如果指向的结构不可公开,则有时只需使用指针类型。这有助于促进数据隐藏。即。

typedef struct hidden_secret_object * object;
void change_object(object foo);

这允许您在不破坏外部代码的情况下更改hidden_secret_object的结构方式。

答案 2 :(得分:5)

我也不清楚。我也不喜欢完全大写的类型(我试着为#defines保留那些)。

这种方式通过认为它实际上是一种值类型而很容易自欺欺人,而我们讨论的是指针类型。可以使用智能指针完全抽象出指针类型,但这在C中并不常见。

后缀(如前所述)_p,_ptr,Pointer或沿着这些线的任何东西都会产生清晰度;增加打字,这是真的,但会阻止你犯愚蠢的错误(例如使用'。'代替' - &gt;',......)会花费你宝贵的开发时间。

答案 3 :(得分:5)

这取决于你想要达到的目标。对于您提出的问题,没有任何有意义的“是或否”答案。

  • 如果您正在尝试创建抽象句柄类型,暗示用户不应该知道或关心隐藏在类型后面的内容,那么键入定义指针类型是完美的精细。重点是,今天它可能是一个指针类型,明天它可能会成为一个整数类型,后来它可能会变成其他东西。这正是指针类型typedef在大多数库接口中通常使用的。

你说有时它“不清楚是否声明指针”。但在这种使用模式下,这正是重点! 假设是“不清楚”。事实上,该类型恰好是一个混淆的指针,这不关你的事。这是你不需要知道而不应该依赖的东西。

此使用模型的典型示例是标准库中的va_list类型。在某些实现中,它可能很容易成为指针类型的typedef。但这是你不应该知道或依赖的东西。

另一个例子是Windows API中HWND类型的定义。它也是指针类型的typedef,但这不关你的事。

  • 完全不同的情况是,当您将指针类型键入为速记形式时,只需要使声明更短,而不必每次都键入*字符。在这种情况下,typedef(并且将始终是)代表指针类型的事实向用户公开。通常这种用法不是一种好的编程习惯。如果用户想要创建别名以避免每次都输入*,他们可以自行完成。

由于您在OP中已经提到的原因,这种使用模式通常会导致代码混淆。

在Windows API中也可以找到typedef使用不当的示例。像PINT这样的Typedef名称完全遵循有缺陷的使用模式。

答案 4 :(得分:1)

如果它是指向不完整类型的指针,或者由于任何其他原因不希望用户取消引用它,我认为这是不好的做法。我从未理解FILE*

我也不认为这样做是不好的,因为你有几个级别的间接,并且你想在一些不相关的情况下使用它。 typedef char **argarray或其他什么。

如果用户需要取消引用它,那么在C中,我认为最好保留*。在C ++中,人们习惯于使用重载operator*的用户定义类型,例如迭代器。在C中,这是不正常的。

答案 5 :(得分:1)

像'const'这样的存储类限定符对typedef指针的作用与使用'自然'指针的作用不同。虽然这对于'const'来说通常不是一件好事,但它对于特定于编译器的存储类(如“xdata”)非常有用。声明如下:

xdata WOKKA *foo;

将“foo”声明为存储在默认存储类中的指针,指向xdata中的WOKKA。声明:

xdata WOKKA_PTR bar;
会将“bar”声明为存储在xdata中的指针,指向WOKKA中指定的任何存储类中的WOKKA。如果库例程需要指向具有特定存储类的东西的指针,那么在指针类型中定义这些存储类可能很有用。

答案 6 :(得分:1)

偶尔会咬我的屁股:

for (vector<typedef_name_that_doesnt_indicate_pointerness_at_all>::iterator it;
    it != v.end(); ++it)
{
   it->foo(); // should have been written (*it)->foo();
}

唯一可接受的是,如果该类型是真正不透明的,并且不能直接访问,那么。 IOW,如果某人不得不在API之外取消引用它,那么指针不应该隐藏在typedef后面。

答案 7 :(得分:0)

也许一种使其更具体的方法是调用新的指针类型type_ptr或类似的东西:

 typedef type_t* type_ptr;