简体   繁体   English

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

[英]C : typedef struct name {...}; VS typedef struct{...} name;

As the title says, I have this code:正如标题所说,我有这个代码:

    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;
    };

I get these errors from gcc :我从 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]

No warnings and no errors occur if I change the typedefs like this:如果我像这样更改 typedef,则不会出现警告和错误:

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

Having searched through C Programming Language, 2nd Edition and googled for a couple of hours, I can't figure out why the first implementation won't work.通过C Programming Language, 2nd Edition搜索并搜索了几个小时,我无法弄清楚为什么第一个实现不起作用。

There are several things going on here.这里发生了几件事。 First, as others have said, the compiler's complaint about unknown type may be because you need to declare the types before using them.首先,正如其他人所说,编译器对未知类型的抱怨可能是因为您需要在使用它们之前声明类型。 More important though is to understand the syntax of 3 things:更重要的是理解三件事的语法:

  1. definition of struct type,结构类型的定义,
  2. definition and declaration of struct variable, and结构变量的定义和声明,以及
  3. typedef类型定义

(Note that in the C-programming language, definition and declaration usually happen at the same time, and thus are essentially the same. This is not the case in many other languages. See footnote below for further details.) (请注意,在 C 编程语言中,定义和声明通常同时发生,因此本质上是相同的。在许多其他语言中情况并非如此。有关详细信息,请参见下面的脚注。)

When defining a struct, the struct can be tagged (named), or untagged (if untagged, then the struct must be used immediately (will explain what this means further below)).定义结构时,结构可以被标记(命名)或未标记(如果未标记,则必须立即使用该结构(将在下面进一步解释这意味着什么))。

struct Name {
   ...
};

This defines a type called "struct Name" which then can be used to define a struct variable/instance:这定义了一个名为“struct Name”的类型,然后可以用来定义一个结构变量/实例:

struct Name myNameStruct;

This defines a variable called myNameStruct which is a struct of type struct Name .这定义了一个名为myNameStruct的变量,它是一个struct Name类型的结构。

You can also define a struct, and declare/define a struct variable at the same time:您还可以定义一个结构,同时声明/定义一个结构变量:

struct Name {
   ...
} myNameStruct;

As before, this defines a variable called myNameStruct which is an instance of type struct Name ... But it does it at the same time it defines the type struct Name .和以前一样,这定义了一个名为myNameStruct的变量,它是struct Name类型的实例......但它同时定义了struct Name类型。
The type can then be used again to declare and define another variable:然后可以再次使用该类型来声明和定义另一个变量:

struct Name myOtherNameStruct;

Now typedef is just a way to alias a type with a specific name:现在typedef只是一种为具有特定名称的类型别名的方法:

typedef OldTypeName NewTypeName;

Given the above typedef, any time you use NewTypeName it is the same as using OldTypeName .鉴于上述 typedef,任何时候使用NewTypeName都与使用OldTypeName相同。 In the C programming language this is particularly useful with structs, because it gives you the ability to leave off the word "struct" when declaring and defining variables of that type and to treat the struct's name simply as a type on its own (as we do in C++).在 C 编程语言中,这对结构特别有用,因为它使您能够在声明和定义该类型的变量时省略“结构”一词,并将结构的名称简单地视为一种类型(正如我们在 C++ 中执行)。 Here is an example that first defines the struct, and then typedefs the struct:这是一个先定义结构,然后对结构进行 typedef 的示例:

struct Name {
   ...
};

typedef struct Name Name_t;

In the above OldTypeName is struct Name and NewTypeName is Name_t .在上面 OldTypeName 是struct Name而 NewTypeName 是Name_t So now, to define a variable of type struct Name, instead of writing:所以现在,要定义一个 struct Name 类型的变量,而不是写:

struct Name myNameStruct;

I can simple write:我可以简单地写:

Name_t myNameStruct;

NOTE ALSO, the typedef CAN BE COMBINED with the struct definition, and this is what you are doing in your code:还要注意,typedef 可以与结构定义结合使用,这就是您在代码中所做的:

typedef struct {
   ...
} Name_t;

This can also be done while tagging (naming) the struct.这也可以在标记(命名)结构时完成。 This is useful for self-referential structs (for example linked-list nodes), but is otherwise superfluous.这对于自引用结构(例如链表节点)很有用,但在其他方面是多余的。 None-the-less, many follow the practice of always tagging structs, as in this example:尽管如此,许多人都遵循始终标记结构的做法,如下例所示:

typedef struct Name {
   ...
} Name_t;

NOTE WELL: In the syntax above, since you have started with "typedef" then the whole statement is a typedef statement, in which the OldTypeName happens to be a struct definition.注意:在上面的语法中,由于您是从“typedef”开始的,那么整个语句就是一个typedef语句,其中 OldTypeName 恰好是一个结构定义。 Therefore the compiler interprets the name coming after the right curly brace } as the NewTypeName ... it is NOT the variable name (as it would be in the syntax without typedef, in which case you would be defining the struct and declaring/defining a struct variable at the same time).因此,编译器将右大括号 }之后的名称解释为 NewTypeName ...它不是变量名称(因为它在没有 typedef 的语法中,在这种情况下,您将定义结构并声明/定义结构变量)。

Furthermore, if you state typedef, but leave off the Name_t at then end, then you have effectively created an INCOMPLETE typedef statement , because the compiler considers everything within " struct Name { ... } " as OldTypeName, and you are not providing a NewTypeName for the typedef.此外,如果您声明 typedef,但在最后省略 Name_t,那么您实际上创建了一个 INCOMPLETE typedef 语句,因为编译器将“ struct Name { ... } ”中的所有内容视为 OldTypeName,并且您没有提供类型定义的新类型名称。 This is why the compiler is not happy with the code as you have written it (although the compiler's messages are rather cryptic because it's not quite sure what you did wrong).这就是为什么编译器对您编写的代码不满意的原因(尽管编译器的消息相当神秘,因为它不太确定您做错了什么)。

Now, as I noted above, if you do not tag (name) the struct type at the time you define it, then you must use it immediately, either to define a variable:现在,正如我上面提到的,如果您在定义它时没有标记(命名)结构类型,那么您必须立即使用它,或者定义一个变量:

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

Or you can use an untagged struct type inside a typedef:或者您可以在 typedef 中使用未标记的结构类型:

typedef struct {
   ...
} Name_t;

This final syntax is what you actually did when you wrote:这个最终的语法是您在编写时实际所做的:

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

And the compiler was happy.编译器很高兴。 HTH. HTH。

Regarding the comment/question about the _t suffix:关于 _t 后缀的评论/问题:

_t suffix is a convention, to indicate to people reading the code that the symbolic name with the _t is a Type name (as opposed to a variable name). _t 后缀是一种约定,用于向阅读代码的人表明带有 _t 的符号名称是类型名称(而不是变量名称)。 The compiler does not parse, nor is it aware of, the _t.编译器不解析,也不知道 _t。

The C89, and particularly the C99, standard libraries defined many types AND CHOSE TO USE the _t for the names of those types. C89,尤其是 C99,标准库定义了许多类型并选择使用 _t 作为这些类型的名称。 For example C89 standard defines wchar_t, off_t, ptrdiff_t.例如 C89 标准定义了 wchar_t、off_t、ptrdiff_t。 The C99 standard defines a lot of extra types, such as uintptr_t, intmax_t, int8_t, uint_least16_t, uint_fast32_t, etc. But _t is not reserved, nor specially parsed, nor noticed by the compiler, it is merely a convention that is good to follow when you are defining new types (via typedef) in C. In C++ many people use the convention to start type names with an uppercase, for example, MyNewType ( as opposed to the C convention my_new_type_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高温高压


Footnote about the differences between declaring and defining : First a special thanks to @CJM for suggesting clarifying edits, particularly in relation to the use of these terms.关于声明定义之间差异的脚注:首​​先特别感谢@CJM 建议澄清编辑,特别是与这些术语的使用有关的内容。 The following items are typically declared and defined : types, variables , and functions .通常声明定义以下项目:类型、变量函数

  • Declaring gives the compiler only a symbolic name and a "type" for that symbolic name.声明只为编译器提供了一个符号名称和该符号名称的“类型”
    • For example, declaring a variable tells the compiler the name of that variable, and its type.例如,声明一个变量会告诉编译器该变量的名称及其类型。
  • Defining gives the complier the full details of an item:定义为编译器提供了项目的全部详细信息:
    • In the case of a type, defining gives the compiler both a name, and the detailed structure for that type.在类型的情况下,定义为编译器提供了名称和该类型的详细结构。
    • In the case of a variable, defining tells the compiler to allocate memory (where and how much) to create an instance of that variable.在变量的情况下,定义告诉编译器分配内存(在哪里和多少)以创建该变量的实例。

Generally speaking, in a program made up of multiple files, the variables, types and functions may be declared in many files, but each may have only one definition .一般来说,在一个由多个文件组成的程序中,变量、类型和函数可以在多个文件中声明,但每个文件可能只有一个定义

In many programming languages (for example C++) declaration and definition are easily separated.在许多编程语言(例如 C++)中,声明和定义很容易分离。 This permits "forward declaration" of types, variables, and functions, which can allow files to compile without the need for these items to be defined until later.这允许类型、变量和函数的“前向声明”,这可以允许文件编译而无需在以后定义这些项目。 In the C programming language however declaration and definition of variables are one and the same .然而,在 C 编程语言中,变量的声明和定义是一回事 (The only exception, that I know of, in the C programming language, is the use of keyword extern to allow a variable to be declared without being defined.) It is for this reason that in a previous edit of this answer I referred to " definition of structs" and " declaration of struct [variables]," where the meaning of " declaration of a struct [variable]" was understood to be creating an instance (variable) of that struct. (据我所知,在 C 编程语言中,唯一的例外是使用关键字extern来允许在不定义变量的情况下声明变量。)正是出于这个原因,在之前编辑的这个答案中,我提到了“结构的定义”和“结构[变量]的声明”,其中“结构[变量]的声明”的含义被理解为创建该结构的实例(变量)。

The syntax is of typedef is as follow: typedef的语法如下:

typedef old_type new_type

In your first try, you defined the struct Book type and not Book .在您的第一次尝试中,您定义了struct Book类型而不是Book In other word, your data type is called struct Book and not Book .换句话说,您的数据类型称为struct Book而不是Book

In the second form, you used the right syntax of typedef , so the compiler recognizes the type called Book .在第二种形式中,您使用了正确的typedef语法,因此编译器可以识别名为Book的类型。

Want to add by clarifying when you actually declare a variable.想要通过澄清何时实际声明变量来添加。

struct foo {
   int a;
} my_foo;

defines foo and immediately declares a variable my_foo of the struct foo type, meaning you can use it like this my_foo.a = 5;定义foo并立即声明struct foo类型的变量my_foo ,这意味着您可以像这样使用它my_foo.a = 5;

However, because typedef syntax follows typedef <oldname> <newname>但是,因为typedef语法遵循typedef <oldname> <newname>

typedef struct bar {
   int b;
} my_bar;

is not declaring a variable my_bar of type struct bar , my_bar.b = 5;没有声明struct bar类型的变量my_barmy_bar.b = 5; is illegal .是非法的 It is instead giving a new name to the struct bar type in the form of my_bar .相反,它以my_bar的形式为struct bar类型提供了一个新名称。 You can now declare the struct bar type with my_bar like this:您现在可以使用my_bar声明struct bar类型,如下所示:

my_bar some_bar;

The other answers are all correct and useful, but maybe longer that necessary.其他答案都是正确且有用的,但可能需要更长的时间。 Do this:做这个:

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 ...
};

You can define the your struct 's in any order provided they only contain pointers to other struct 's.您可以按任何顺序定义您的struct ,前提是它们只包含指向其他struct的指针。

You just need to define Author before defining Book.您只需要在定义 Book 之前定义 Author。

You use Author in Book so it needs to be defined before.您在 Book 中使用 Author,因此需要在之前对其进行定义。

I think is going to help you understand.我想会帮助你理解。 http://www.tutorialspoint.com/cprogramming/c_typedef.htm 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’

These are produced because you have to define them before you use them.产生这些是因为您必须在使用它们之前定义它们。 Move the struct "Author" & "Books" above the struct "Book".将结构“作者”和“书籍”移动到结构“书”上方。 This will solve it.这将解决它。

Also the warning you are getting explains why there is a problem, the compiler identifies "typedef struct Author" as not necessary because you are not properly typedef the struct so there is nothing useful for the compiler to "read".此外,您收到的警告解释了为什么存在问题,编译器将“typedef struct Author”标识为不必要,因为您没有正确地对结构进行 typedef,因此编译器“读取”没有任何用处。

Since you already know the answer should be in this form既然你已经知道答案应该是这种形式

typedef struct {
 ...
 ... 
 ...
} struct-name;

stick with that.坚持下去。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM