【问题标题】:In C, is it good form to use typedef for a pointer?在 C 中,将 typedef 用于指针是一种好的形式吗?
【发布时间】:2013-06-12 16:04:36
【问题描述】:

考虑以下 C 代码:

typedef char * MYCHAR;
MYCHAR x;

我的理解是,结果将是 x 是“char”类型的指针。然而,如果 x 的声明发生在远离 typedef 命令的地方,代码的人类读者不会立即知道 x 是一个指针。或者,可以使用

typedef char MYCHAR;
MYCHAR *x;

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

【问题讨论】:

  • 这是一个品味问题(和编码规则)。就个人而言,我不喜欢在typedef 中隐藏“指针”,所以我根本不喜欢typedef char* MYSTRING;...

标签: c pointers typedef


【解决方案1】:

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

否则,最好明确类型的“指针”。

【讨论】:

  • 指向不完整类型的指针作为函数参数完全有效,您也不能取消引用它们。 IOW:您不需要将它们隐藏在愚蠢的 typedef 后面,甚至在“秘密”API 中也不需要。
  • @wildplasser:我认为重点不是在不透明类型中隐藏指针(您只是传递)是一种好习惯,而是在必须隐藏指针时隐藏指针是不好的做法被这样对待(例如可怕的typedef char * string;)。
  • 简单明了的回答。不妨添加一个事实,即在创建指针类型时,可能需要创建它们的const-qualified 版本,原因您肯定知道。
【解决方案2】:

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

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

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

但如果用户应该理解该类型实际上是一个指针并且可以用作指针,那么指针类型定义会严重混淆代码。我会避开他们。显式声明指针使代码更具可读性。

有趣的是,C 标准库避免了这种指针类型定义。例如,FILE 显然打算用作不透明类型,这意味着库可以将其定义为typedef FILE <some pointer type>,而不是让我们一直使用FILE *。但出于某种原因,他们决定不这样做。

【讨论】:

    【解决方案3】:

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

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

    可以说比:

    char *str1, str2, str3;  // oops
    

    【讨论】:

    • 这是一个很好的结果,但这个结果本身就是 typedef 的一个坏理由 :)
    【解决方案4】:

    我更喜欢留下*,它表明有一个指针。而你的第二个例子应该缩写为char* x;,这没有意义。

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

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

        声明指针类型有用的其他情况是参数的性质对用户(程序员)不透明。可能有 API 想要将指针返回给用户,并期望用户在其他时间将其传递回 API。像不透明的句柄或 cookie 一样,仅供 API 在内部使用。用户不关心参数的性质。通过在 API 中暴露 * 来避免混淆或暴露其确切性质是有意义的。

        【讨论】:

          【解决方案7】:

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

          可能还有很多其他人。

          【讨论】:

            【解决方案8】:

            对于 API,不需要将结构定义和指针隐藏在“抽象”类型定义后面。

                    /* 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;
            }
            

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

            【讨论】:

              【解决方案9】:

              这不仅仅是风格问题吗?

              是的。例如,这个:

              typedef int *ip;
              const ip p;
              

              不等于:

              const int *p; // p is non-const pointer to const int
              

              同理:

              int * const p; // p is constant pointer to non-const int
              

              在此处typedef pointer const weirdness 阅读有关 typedef 的 const 怪异之处@

              【讨论】:

                猜你喜欢
                • 2010-10-19
                • 2023-01-24
                • 2011-08-30
                • 2016-01-13
                • 2011-02-09
                • 1970-01-01
                • 2011-01-28
                • 1970-01-01
                相关资源
                最近更新 更多