61

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

    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搜索并搜索了几个小时,我无法弄清楚为什么第一个实现不起作用。

4

6 回答 6

154

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

定义结构时,结构可以是命名的,也可以是未命名的(如果未命名,则必须立即使用它(将在下面进一步解释这意味着什么))。

struct Name {
   ...
};

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

struct Name myNameStruct;

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

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

struct Name {
   ...
} myNameStruct;

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

struct Name myOtherNameStruct;

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

typedef OldTypeName NewTypeName;

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

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 ...它不是变量名称(因为它在没有 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 相对)。高温高压

于 2014-05-14T16:20:19.153 回答
7

的语法typedef如下:

typedef old_type new_type

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

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

于 2013-07-18T10:09:42.333 回答
2

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

struct foo {
   int a;
} my_foo;

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

但是,因为typedef语法如下typedef <oldname> <newname>

typedef struct bar {
   int b;
} my_bar;

不声明类型的变量,是非法。相反,它以. 您现在可以像这样声明类型:my_barstruct barmy_bar.b = 5; struct barmy_barstruct barmy_bar

my_bar some_bar;
于 2019-11-07T20:20:31.490 回答
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按任何顺序定义 your ,前提是它们只包含指向otherstruct的指针。

于 2020-11-20T06:54:19.663 回答
0

您只需要在定义 Book 之前定义 Author。

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

于 2013-07-18T10:07:47.060 回答
0

我想会帮助你理解。 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;

坚持下去。

于 2013-07-18T10:12:51.380 回答