【问题标题】:typedef a struct before it's declared在声明之前 typedef 一个结构
【发布时间】:2012-11-29 12:51:17
【问题描述】:

我不是初学者,对下面的成语很熟悉:

typedef struct Foo_ Foo;// I know typedef struct Foo Foo is fine, I'm just trying to make it clearer
struct Foo_
{
    int value;
    Foo *link;
};

我只是突然感到困惑,因为我的理解是在声明之前不允许使用名称(标识符)。但是在声明typedef struct Foo_ Foo 中,标识符Foo_ 还不存在!编译器怎么会允许这种情况发生?请有人对此有所了解,向我解释这种语法的理由是什么?

维基百科引用:typedef 的目的是为现有类型分配替代名称。

--- >8 ---

感谢大家提供这么多有用的信息。

【问题讨论】:

    标签: c typedef


    【解决方案1】:

    这完全没问题。像您这样的struct 标签的第一次使用是struct 类型的前向声明。

    请注意,尽管您对_Foo 的使用符合要求。保留带有前导下划线和后跟大写字母的标识符。不要那样做。尾随下划线可以。

    【讨论】:

    • 这是否意味着typedef struct Foo_ Foo实际上是struct Foo_; typedef struct Foo_ Foo;合并在一起的?
    • 我明白了,这确实有道理,因为我们可以写类似typedef struct Foo {...} Foo; 的东西,而typedef struct Foo Foo; 只是省略了{...} 部分。
    • 嗯,非常好的线程。我也明白。因此,编译器实际上只有在看到 { 而不是 ; 时的结构,也就是说,只有在设置了 struct foo { ...} foo struct 时才有多少 struct foo;`。即使包括-Wall -Wextra,以下示例也可以正常工作:struct foo; struct foo; struct foo { int a, b, c; char *s; };
    【解决方案2】:

    这在 6.7.2.3p8 中有介绍:

    6.7.2.3 标签

    语义
    [...]

    8 - 如果 struct-or-union identifier 形式的类型说明符出现在 [a struct-or-union definition] 或 [a struct-or-union declaration] 之外,并且没有其他声明 标识符作为标记是可见的,然后它声明一个不完整的结构或联合类型,并且 将标识符声明为该类型的标记。

    typedef struct Foo Foo 中的类型说明符 struct Foo 不在定义 (struct Foo {...};) 或声明 (struct Foo;) 中,因此它属于 6.7.2.3p8。

    请注意,typedef 没有什么特别之处;你也可以例如写

    struct A { struct Foo *p; };
    

    之前的定义或声明不需要可见。

    但是,在函数声明或定义中:

    void foo(struct Foo *p);
    

    如果struct Foo 之前没有声明,那么声明的作用域 将只是函数声明或定义,它不会与@987654329 的任何后续声明或定义类型兼容@。

    【讨论】:

      【解决方案3】:
      ISO c99 : 6.2.1 Scopes of identifiers
      

      7

      结构、联合和枚举标记的范围紧随其出现之后开始 声明标签的类型说明符中的标签。

      typedef struct _Foo Foo; // You can do this because it's just the typedef the new type
      
      struct _Foo *myfoo ; // It's pointer to struct _Foo (an incomplete type)
                            //but make sure before using myfoo->value   
                          // struct definition should be available
      
      struct _Foo MyFoo;  // It's  definition of MyFoo but don't forget 
                          // to give the definition of struct _Foo (gcc extension). 
      
      struct _Foo;  // forward declaration
      
      struct _Foo    // It's the definition
      {
          int value;
          Foo *link;
      };
      

      对于functions,我们在实际定义函数之前做forward declarationtypedef,所以我们也可以用struct来做。

      void func(int );
      typedef void (*func_t)(int);
      
      void func(int x)
      {
       //actual definition
      }
      

      【讨论】:

        【解决方案4】:

        typedef 用于为一个类型创建一个别名。但在 typedef 时,该类型不一定存在。

        例如,

        如果你这样做:

        struct Foo;
        

        而且你从来没有在程序的任何地方定义struct Foo,那么它仍然会编译。 编译器会假设它在某处定义并继续。只有在不定义结构的情况下使用它,才会出现错误。

        typedef 也是如此。

        【讨论】:

        • 没有。 AFAIK,struct Foo * myFoo 可以,但struct Foo myFoo 不行,因为它的大小未知。
        • 我想你的意思是struct Foo; 这是Foo 的前向声明
        • @mux 它给你错误,因为你没有给出定义..你可以做到struct foo myfoo;,但必须在struct foo myfoo声明之后提供struct foo;的定义;我认为它可能是 gcc 对 struct 的一些扩展,并且使用 gcc 而不是 g++ 编译它会成功编译
        • @Omkant 不完整类型是可以的,而 struct Foo myFoo 需要完整类型。 mux 是正确的,但在我更新后,他的评论变得过时了,这导致了现在的混乱。很抱歉:)
        • @KingsIndian:不不,我只是去了mux在此处发布的链接并进行了一些修改,如果请访问链接ideone.com/BSOH7N并查看它是否有效,这是我的困惑,是标准的这么说或者是gcc扩展
        【解决方案5】:

        在某些情况下,在声明之前使用struct ... 类型是有效的。那就是所谓的“不完全类型”。

        例如,将变量声明为指向“不完整”结构的指针以及(如您所见)typedef 是有效的。

        【讨论】:

          【解决方案6】:

          这称为前向声明。前向声明允许您在允许不完整类型的上下文中使用其名称。

          编译器会“看到” typedef 标签,并将其存储起来,直到找到类型,所以只要你在 typedef 之后,但在任何使用之前,都在其中声明了类型,就可以了。

          【讨论】:

            【解决方案7】:

            typedef 声明允许您定义自己的标识符,这些标识符可以用来代替类型说明符,例如 int、float 和 double。 typedef 声明不保留存储空间。

            更多信息http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=%2Fcom.ibm.vacpp6m.doc%2Flanguage%2Fref%2Fclrc03typdef.htm

            【讨论】:

            • 这与问题无关。
            • @Kiril Kirov 正如您在您的问题中所解释的那样,我的理解是在声明之前不允许使用名称(标识符)。但是在声明 typedef struct _Foo Foo 中,标识符 _Foo 还不存在!但是 typedef 不检查它的存在..那是我正在写答案...尝试再次阅读然后分析它。
            • 我不是发布问题的人,我知道可以这样做(ISO标准中甚至有这样的例子),我只是认为您的答案与问题。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-12-23
            • 2023-03-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多