C : typedef 结构名称 ...; VS typedef struct... 名称;

Posted

技术标签:

【中文标题】C : typedef 结构名称 ...; VS typedef struct... 名称;【英文标题】:C : typedef struct name ...; VS typedef struct... name;C : typedef 结构名称 ...; VS typedef struct... 名称; 【发布时间】:2013-07-17 05:05:45 【问题描述】:

正如标题所说,我有这个代码:

    typedef struct Book
        int id;
        char title[256];
        char summary[2048];
        int numberOfAuthors;
        struct Author *authors;
    ;


    typedef struct Author
        char firstName[56];
        char lastName[56];
    ;


    typedef struct Books
        struct Book *arr;
        int numberOfBooks;
    ;

我从 gcc 得到这些错误:

bookstore.c:8:2: error: unknown type name ‘Author’
bookstore.c:9:1: warning: useless storage class specifier in empty declaration [enabled by default]
bookstore.c:15:1: warning: useless storage class specifier in empty declaration [enabled by default]
bookstore.c:21:2: error: unknown type name ‘Book’
bookstore.c:23:1: warning: useless storage class specifier in empty declaration [enabled by default]

如果我像这样更改 typedef,则不会出现警告和错误:

    typedef struct
        char firstName[56];
        char lastName[56];
     Author;

通过 C Programming Language, 2nd Edition 搜索并搜索了几个小时,我无法弄清楚为什么第一个实现不起作用。

【问题讨论】:

Author 移到Book 之前。另请注意,您的 typedefs 是多余的 Author 结构中的更改怎么可能同时删除error:unknown type name ‘Book’?请看一下here,它清楚地提到了 typdef 结构和仅定义结构之间的区别。 【参考方案1】:

其他答案都是正确且有用的,但可能需要更长的时间。这样做:

typedef struct Book Book;
typedef struct Books Books;
typedef struct Author Author;

struct Book 
    ... as you wish ...
;

struct Author 
    ... as you wish ...
;

struct Books 
    ... as you wish ...
;

您可以按任何顺序定义您的struct,只要它们只包含指向其他struct指针

【讨论】:

【参考方案2】:

想要通过澄清何时实际声明变量来添加。

struct foo 
   int a;
 my_foo;

定义foo并立即声明struct foo类型的变量my_foo,意味着你可以像这样使用它my_foo.a = 5;

但是,因为typedef 语法遵循typedef <oldname> <newname>

typedef struct bar 
   int b;
 my_bar;

声明了struct barmy_bar.b = 5; 类型的变量my_bar 是非法的 .相反,它以my_bar 的形式为struct bar 类型提供了一个新名称。你现在可以像这样用my_bar 声明struct bar 类型:

my_bar some_bar;

【讨论】:

【参考方案3】:

这里发生了几件事。首先,正如其他人所说,编译器对未知类型的抱怨可能是因为您需要在使用它们之前定义类型。更重要的是理解三件事的语法:(1) 结构定义,(2) 结构声明,和 (3) typedef。

当定义一个结构体时,该结构体可以是命名的,也可以是未命名的(如果未命名,那么它必须立即使用(下面会解释这意味着什么))。

struct Name 
   ...
;

这定义了一个名为“struct Name”的类型,然后可以用来声明一个结构变量:

struct Name myNameStruct;

这声明了一个名为myNameStruct 的变量,它是一个struct Name 类型的结构。

你也可以定义一个struct,同时声明一个struct变量:

struct Name 
   ...
 myNameStruct;

和以前一样,这声明了一个名为 myNameStruct 的变量,它是一个 struct Name 类型的结构 ... 但它同时定义了类型 struct Name。 该类型可以再次用于声明另一个变量:

struct Name myOtherNameStruct;

现在 typedef 只是一种为具有特定名称的类型设置别名的方法:

typedef OldTypeName NewTypeName;

鉴于上述 typedef,任何时候使用 NewTypeName 都与使用 OldTypeName 相同。 在 C 编程语言中,这对结构特别有用,因为它使您能够在声明该类型的变量时省略“结构”一词,并将结构的名称简单地视为它自己的(就像我们在 C++ 中所做的那样)。下面是一个先定义结构体,然后对结构体进行typedef的例子:

struct Name 
   ...
;

typedef struct Name Name_t;

在上面的 OldTypeName 是 struct Name 而 NewTypeName 是 Name_t。所以现在,要声明一个 struct Name 类型的变量,而不是写:

struct Name myNameStruct;

我可以简单地写:

Name_t myNameStruct;

还要注意,typedef 可以与结构定义结合使用,这就是您在代码中所做的:

typedef struct 
   ...
 Name_t;

这也可以在命名结构时完成,但这是多余的:

typedef struct Name 
   ...
 Name_t;

注意:在上面的语法中,由于您以“typedef”开头,因此整个语句是typedef 语句,其中 OldTypeName 恰好是一个结构定义。因此,编译器将 右花括号 之后的名称解释为 NewTypeName ...它是 NOT 变量名(就像在没有 typedef 的语法中一样,在这种情况下,您将同时定义结构和声明结构变量)。

此外,如果您声明 typedef,但在末尾省略 Name_t,那么您实际上创建了一个 INCOMPLETE typedef 语句,因为编译器将“struct Name ... ”中的所有内容视为 OldTypeName,并且您没有为 typedef 提供 NewTypeName。这就是编译器对您编写的代码不满意的原因(尽管编译器的消息相当神秘,因为它不太确定您做错了什么)。

现在,正如我上面提到的,如果你在定义它的时候没有命名结构类型,那么你必须立即使用它来声明一个变量:

struct 
   ...
 myNameStruct;  // declares myNameStruct as a variable with this struct
                 // definition, but the definition cannot be re-used.

或者您可以在 typedef 中使用未命名的结构类型:

typedef struct 
   ...
 Name_t;

这个最终的语法是你在编写时实际所做的:

typedef struct
   char firstName[56];
   char lastName[56];
 Author;

编译器很高兴。 HTH。

关于 _t 后缀的评论/问题:

_t 后缀是一种约定,用于向阅读代码的人表明带有 _t 的符号名称是类型名称(而不是变量名称)。编译器不解析,也不知道 _t。

C89,尤其是 C99,标准库定义了许多类型,并选择使用 _t 作为这些类型的名称。例如 C89 标准定义了 wchar_t、off_t、ptrdiff_t。 C99标准定义了很多额外的类型,比如uintptr_t、intmax_t、int8_t、uint_least16_t、uint_fast32_t等。但是_t不是保留的,也不是专门解析的,也不是被编译器注意到的,它只是一个很好遵循的约定当您在 C 中定义新类型(通过 typedef)时。在 C++ 中,许多人使用约定以大写开头的类型名称,例如 MyNewType(与 C 约定 my_new_type_t 相对)。高温

【讨论】:

我们可以用_t 后缀声明任何类型吗?我以为这个后缀是 C99 保留的。我错了吗? 重要的是要注意自引用结构需要结构名称或前向声明的 typedef。例如,如果我想要一个类型化的 LinkedList 节点,我更喜欢这样写:typedef struct node_t void * data; struct node_t next; Node;,以便声明完整而简洁。 说真的,这解决了我对 C 结构的所有困惑。谢谢! @MTV "Because the struct type is unnamed, you can't declare another such variable. So there can only ever be one instance of that type right?" 没错。这就是为什么你很少会使用匿名结构的原因。我唯一一次做过这样的事情是,如果我只是暂时需要一个函数内部的局部结构。当然,如果您需要将数据传递到其他任何地方,您可以命名该结构,或者更常见的是 typedef 它。如果多个文件需要访问结构定义,您可以将其放在头文件中。希望对您有所帮助。 struct Name ; 中的Name 称为结构的标签。编译器使用此标记来查找定义。这很重要,因为如果您的结构引用自身(例如在链表中),那么您必须使用标记结构,否则,typedef 声明尚未完成,编译器不知道类型名称. AFAIK 这是这两种定义结构的方式之间的唯一区别。【参考方案4】:

我想这会帮助你理解。 http://www.tutorialspoint.com/cprogramming/c_typedef.htm

bookstore.c:8:2: error: unknown type name ‘Author’
bookstore.c:21:2: error: unknown type name ‘Book’

产生这些是因为您必须在使用它们之前定义它们。将结构“作者”和“书籍”移动到结构“书”上方。这样就解决了。

您收到的警告还解释了为什么会出现问题,编译器将“typedef struct Author”标识为不必要,因为您没有正确地对结构进行 typedef,因此编译器“读取”没有任何用处。

既然你已经知道答案应该是这种形式

typedef struct 
 ...
 ... 
 ...
 struct-name;

坚持下去。

【讨论】:

【参考方案5】:

typedef的语法如下:

typedef old_type new_type

在您的第一次尝试中,您定义了 struct Book 类型和 not Book。换句话说,您的数据类型称为struct Book 而不是Book

在第二种形式中,您使用了正确的 typedef 语法,因此编译器可以识别名为 Book 的类型。

【讨论】:

这只是简单情况的语法,反例是typedef int x[5];,或typedef int (*p)();【参考方案6】:

你只需要在定义书之前定义作者。

您在 Book 中使用 Author,因此需要在之前对其进行定义。

【讨论】:

感谢您的快速回复。在 Author 之前定义 Book 没有错误,在 Kernighan 和 Ritchie 的书中检查过。 我错了,显然如果我改变位置它确实会消除错误。我必须多学习一点。 (抱歉重复评论,*** 中的第一个计时器:P)

以上是关于C : typedef 结构名称 ...; VS typedef struct... 名称;的主要内容,如果未能解决你的问题,请参考以下文章

C语言中的typedef是啥意思啊

Linux C/C++关于结构体定义,typedef关键字的使用场景

typedef struct vs struct - “struct”的存储大小未知[重复]

C语言基础:typedef关键字 typedef vs #define

为啥 typedef 的名称可以用作结构成员的名称?

Rust有相当于C的typedef吗?