繁体   English   中英

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

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

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

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

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

  1. 结构类型的定义,
  2. 结构变量的定义和声明,以及
  3. 类型定义

(请注意,在 C 编程语言中,定义和声明通常同时发生,因此本质上是相同的。在许多其他语言中情况并非如此。有关详细信息,请参见下面的脚注。)

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

struct Name {
   ...
};

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

struct Name myNameStruct;

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

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

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 ...它不是变量名称(因为它在没有 typedef 的语法中,在这种情况下,您将定义结构并声明/定义结构变量)。

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

现在,正如我上面提到的,如果您在定义它时没有标记(命名)结构类型,那么您必须立即使用它,或者定义一个变量:

struct {
   ...
} myNameStruct;  // defines myNameStruct as a variable with this struct
                 // definition, but the struct 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 相对)。 高温高压


关于声明定义之间差异的脚注:首​​先特别感谢@CJM 建议澄清编辑,特别是与这些术语的使用有关的内容。 通常声明定义以下项目:类型、变量函数

  • 声明只为编译器提供了一个符号名称和该符号名称的“类型”
    • 例如,声明一个变量会告诉编译器该变量的名称及其类型。
  • 定义为编译器提供了项目的全部详细信息:
    • 在类型的情况下,定义为编译器提供了名称和该类型的详细结构。
    • 在变量的情况下,定义告诉编译器分配内存(在哪里和多少)以创建该变量的实例。

一般来说,在一个由多个文件组成的程序中,变量、类型和函数可以在多个文件中声明,但每个文件可能只有一个定义

在许多编程语言(例如 C++)中,声明和定义很容易分离。 这允许类型、变量和函数的“前向声明”,这可以允许文件编译而无需在以后定义这些项目。 然而,在 C 编程语言中,变量的声明和定义是一回事 (据我所知,在 C 编程语言中,唯一的例外是使用关键字extern来允许在不定义变量的情况下声明变量。)正是出于这个原因,在之前编辑的这个答案中,我提到了“结构的定义”和“结构[变量]的声明”,其中“结构[变量]的声明”的含义被理解为创建该结构的实例(变量)。

typedef的语法如下:

typedef old_type new_type

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

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

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

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 bar类型的变量my_barmy_bar.b = 5; 是非法的 相反,它以my_bar的形式为struct bar类型提供了一个新名称。 您现在可以使用my_bar声明struct bar类型,如下所示:

my_bar some_bar;

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

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的指针。

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

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

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

坚持下去。

暂无
暂无

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

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