在C中,使用typedef指针是一种好的forms吗?

考虑以下C代码:

typedef char * MYCHAR; MYCHAR x; 

我的理解是结果是x是“char”类型的指针。 但是,如果x的声明远离typedef命令,则代码的人类读者不会立即知道x是指针。 或者,可以使用

 typedef char MYCHAR; MYCHAR *x; 

哪个被认为是更好的forms? 这不仅仅是风格问题吗?

我只会在结果类型的指针性质没有意义的情况下使用指针typedef。 例如,当想要声明一个不透明的“句柄”类型时,指针typedef是合理的,它恰好被实现为一个指针,但不应该被用户用作指针。

 typedef struct HashTableImpl *HashTable; /* 'struct HashTableImpl' is (or is supposed to be) an opaque type */ 

在上面的示例中, HashTable是哈希表的“句柄”。 用户最初将从CreateHashTable函数接收该句柄,并将其传递给HashInsert函数等。 用户不应该关心(或者甚至知道) HashTable是指针。

但是在用户应该理解该类型实际上是指针并且可用作指针的情况下,指针typedef会使代码混淆不清。 我会避免他们。 明确声明指针使代码更具可读性。

有趣的是,C标准库避免了这种指针类型的定义。 例如, FILE显然是用作opaque类型,这意味着库可以将它定义为typedef FILE 而不是让我们一直使用FILE * 。 但由于某种原因,他们决定不这样做。

如果指针永远不会被解除引用或直接操作 – IOW,你只将它作为参数传递给API – 那么可以将指针隐藏在typedef后面。

否则,最好使类型的“指针”显式化。

我并不特别喜欢指向typedef,但它有一个优点。 当您在单个声明中声明多个指针变量时,它可以消除混淆和常见错误。

 typedef char *PSTR; ... PSTR str1, str2, str3; 

可以说比以下更清楚:

 char *str1, str2, str3; // oops 

我更喜欢离开* ,它表明有一个指针。 你的第二个例子应缩短为char* x; , 这没有道理。

我也认为这是风格/惯例的问题。 在Apple的Core Graphics库中,他们经常“隐藏”指针,并使用将“Ref”附加到类型末尾的约定。 例如, CGImage *对应于CGImageRef 。 这样你仍然知道它是一个指针引用。

另一种看待它的方法是从类型的角度来看。 类型定义该类型可能的操作,以及调用这些操作的语法。 从这个角度来看,MYCHAR就是它的全部。 程序员有责任了解其允许的操作。 如果它被声明为第一个示例,则它支持*运算符。 您始终可以适当地命名标识符以阐明其用途。

声明作为指针的类型有用的其他情况是参数的性质对用户(程序员)不透明的情况。 可能有API想要返回指向用户的指针,并期望用户在某个其他点将其传递回API。 像不透明的句柄或cookie一样,API仅在内部使用。 用户不关心参数的性质。 通过在API中暴露*来淹没水域或暴露其确切性质是有道理的。

如果您查看几个现有的API,看起来好像没有将指针放入类型似乎更好的样式:

  • 已提及的FILE *
  • MySQL的mysql_real_connect()返回的MYSQL *
  • MySQL的mysql_store_result()mysql_use_result()返回的MYSQL *

可能还有很多其他人。

对于API, 没有必要隐藏“抽象”typedef背后的结构定义和指针。

  /* This is part of the (hypothetical) WDBC- API ** It could be found in wdbc_api.h ** The struct connection and struct statement ar both incomplete types, ** but we are allowed to use pointers to incomplete types, as long as we don't ** dereference them. */ struct connection *wdbc_connect (char *connection_string); int wdbc_disconnect (struct connection *con); int wdbc_prepare (struct connection * con, char *statement); int main(void) { struct connection *conn; struct statement *stmt; int rc; conn = wdbc_connect( "host='localhost' database='pisbak' username='wild' password='plasser'" ); stmt = wdbc_prepare (conn, "Select id FROM users where name='wild'" ); rc = wdbc_disconnect (conn); return 0; } 

上面的片段编译得很好。 (但显然无法链接)