【问题标题】:Typedefs, tagged and untagged structures, and incompatible pointer typesTypedef、标记和未标记的结构以及不兼容的指针类型
【发布时间】:2012-09-24 09:43:03
【问题描述】:

考虑以下 C 代码 sn-p:

typedef struct node{
    int val;
    struct node* left;
    struct node* right;
}node;

void inorderTraversal(node *p){
    inorderTraversal(p->left);
    printf("%d",p->val);
    inorderTraversal(p->right);
}

如果我只写typedef struct 而不是typedef struct node,当我在main() 中调用inorderTraversal(root) 时,我会收到一条警告说“传递不兼容指针类型的参数”。为什么即使程序没有显示任何错误,我也会收到此警告?

【问题讨论】:

    标签: c struct typedef


    【解决方案1】:

    如果你不给结构一个标签名,

    struct node* left;
    

    在结构定义中声明了一个新的(不完整的)类型struct node。因此,当您传递一个指向该(不完整)类型的指针时,需要 node*,您传递的是一个不兼容类型的指针。

    当您定义的结构具有指向同一类型的指针时,您必须能够在定义中命名该类型,因此该类型必须在范围内。

    如果您给struct 命名,则该类型 - 从那时起 - 在范围内,尽管尚未完成,但可以引用为struct node(如果标签是node)。在 typedef 完成后,类型可以被称为 struct nodenode,无论你喜欢哪个。

    但是如果你不给struct 一个标签,在typedef 完成之前类型是匿名的,并且在此之前不能以任何方式被引用。而自从当行

    struct node *left;
    

    遇到,struct node 所指的类型未知,该行声明了一个新类型 struct node,对此一无所知。编译器没有理由将该类型与当前定义的类型联系起来。因此,此时,struct 包含一个成员,该成员是指向未知不完整类型的指针。现在,在inorderTraversal,当你打电话时

    inorderTraversal(p->left);
    

    对于node *p,根据node 的定义,p->left 是一个指向未知不完整类型struct node 的指针。如果已创建 p 以使 p->left 实际上是指向 node 的指针,那么事情仍然会起作用(可能在指向不同类型的指针具有不同表示的平台上除外),但是您正在传递指向一种类型的指针需要指向不同类型的指针。由于一种类型不完整,因此与预期类型不兼容。

    【讨论】:

      【解决方案2】:
      "passing argument of incompatible pointer type"
      

      因为当时节点是未知的。所以它被认为是一种新类型。

      struct node{
          int val;
          struct node* left;
          struct node* right;
      };
      
      void inorderTraversal(struct node *p){
          inorderTraversal(p->left);
          printf("%d",p->val);
          inorderTraversal(p->right);
      }
      

      现在节点在使用它之前被声明为结构。即struct node* left; 所以没有错误。

      也请参考:self referential struct definition?
      C structure with pointer to self

      【讨论】:

      • 这很好,但我不想这样做。我知道这个。我想知道我的代码发出警告的原因。
      【解决方案3】:

      你不能创建一个匿名的typedef,它必须有一个名字。 C 不支持匿名struct 类型。

      一个 GCC 扩展将启用该功能:-fms-extensions

      【讨论】:

      • 你可以 typedef 一个没有标签的结构,你只是不能在它自己的定义中引用它。
      • 这在 C89 中曾经有很多编译器的情况,但 C99 允许这样做。事实上,在 C99 中,可以返回函数声明中定义的匿名结构/枚举/联合,也可以使用匿名结构/枚举/联合定义全局变量和常量(包括数组)。
      猜你喜欢
      • 1970-01-01
      • 2018-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多