C:typedef struct name {...}; VS typedef struct {...}名称;

Ale*_*zyk 40 c struct typedef

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

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;
};
Run Code Online (Sandbox Code Playgroud)

我从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]
Run Code Online (Sandbox Code Playgroud)

如果我像这样更改typedef:

typedef struct{
    char firstName[56];
    char lastName[56];
} Author;
Run Code Online (Sandbox Code Playgroud)

然后没有警告,也没有错误发生.通过http://www.amazon.com/C-Programming-Language-2nd-Edition/dp/0131103628搜索了几个小时的谷歌搜索,我无法弄清楚为什么第一个实现不起作用.

Dan*_*arb 100

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

定义结构时,结构可以命名或未命名(如果未命名,则必须立即使用(将解释这意味着在下面进一步说明)).

struct Name {
   ...
};
Run Code Online (Sandbox Code Playgroud)

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

struct Name myNameStruct;
Run Code Online (Sandbox Code Playgroud)

这声明了一个名为myNameStructstruct的类型的变量struct Name.

您还可以定义结构,并同时声明结构变量:

struct Name {
   ...
} myNameStruct;
Run Code Online (Sandbox Code Playgroud)

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

struct Name myOtherNameStruct;
Run Code Online (Sandbox Code Playgroud)

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

typedef OldTypeName NewTypeName;
Run Code Online (Sandbox Code Playgroud)

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

struct Name {
   ...
};

typedef struct Name Name_t;
Run Code Online (Sandbox Code Playgroud)

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

struct Name myNameStruct;
Run Code Online (Sandbox Code Playgroud)

我可以简单地写一下:

Name_t myNameStruct;
Run Code Online (Sandbox Code Playgroud)

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

typedef struct {
   ...
} Name_t;
Run Code Online (Sandbox Code Playgroud)

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

typedef struct Name {
   ...
} Name_t;
Run Code Online (Sandbox Code Playgroud)

注意:在上面的语法中,由于您已经开始使用"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.
Run Code Online (Sandbox Code Playgroud)

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

typedef struct {
   ...
} Name_t;
Run Code Online (Sandbox Code Playgroud)

这个最终语法是您在编写时实际执行的操作:

typedef struct{
   char firstName[56];
   char lastName[56];
} Author;
Run Code Online (Sandbox Code Playgroud)

编译器很高兴.HTH.

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

_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).HTH

  • 值得注意的是,自引用结构需要结构的名称或前向声明的typedef.我更喜欢,例如,如果我想要一个类型化的LinkedList节点写:`typedef struct node_t {void*data; struct node_t next; } Node;`这样声明完整而简洁. (3认同)
  • 说真的,这解决了我对C struct的困惑.谢谢! (3认同)
  • 我们可以用`_t`后缀声明任何类型吗?我以为这个后缀是C99保留的。我错了吗? (2认同)
  • @MTV“因为结构类型是未命名的,所以你不能声明另一个这样的变量。所以只能有一个该类型的实例,对吧?”这是正确的。这就是为什么您很少会使用匿名结构。我唯一一次做过这样的事情是如果我只是暂时需要函数内的本地结构。当然,如果您需要将数据传递到其他地方,您可以命名该结构,或更常见的是 typedef 它。如果多个文件需要访问结构定义,您可以将其放入头文件中。希望有帮助。 (2认同)

Bec*_*hir 5

语法typedef如下:

typedef old_type new_type
Run Code Online (Sandbox Code Playgroud)

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

在第二种形式中,您使用了正确的语法typedef,因此编译器会识别所调用的类型Book.