【问题标题】:Why must the 'struct' keyword precede struct instances in C?为什么'struct'关键字必须在C中的结构实例之前?
【发布时间】:2017-11-29 14:58:32
【问题描述】:

假设我在 C 中定义了一个结构。如果我声明该结构的一个实例,则必须在其前面包含“结构”关键字。

// Define struct
struct Book {
   char title[50];
   char author[50];
   char subject[100];
   int book_id;
};

// Instantiate struct
int main()
{
    struct Book myBook;
}

我的问题:为什么结构关键字必须在结构的任何实例化之前?似乎编译器有大量信息可以推断出 'Book' 是一个结构。

我知道你可以通过使用 typedef 来解决这个问题,但这看起来就像是编译器应该已经知道的样板代码。

【问题讨论】:

  • 在 C 中,结构和联合都有自己的命名空间,不同于全局命名空间。你必须说struct,所以它知道在结构命名空间中查找。
  • @RaymondChen:标签命名空间在结构、联合和枚举之间共享 - 例如,您不能在同一范围内同时拥有 struct foounion foo。标签有自己的命名空间,structunion 成员也是如此。所有其他标识符(变量名、函数名、枚举常量等)都集中在“普通标识符”命名空间中。

标签: c struct typedef


【解决方案1】:

由于使用关键字 struct、union 和 enum,这些类型的名称可以形成自己的命名空间,不会与其他实体的名称冲突。

例如

#include <stdio.h>

int main(void) 
{
    struct Book 
    {
        const char *Book;
    } Book = { "The first favorite book" };

    struct Book otherBook = { .Book = "The second favorite book" };

    puts( Book.Book );
    puts( otherBook.Book );

    return 0;
}

【讨论】:

  • 判断这是否是一个足够严重的优势来抵消一直写struct 的烦恼(或使用typedef 技巧,这在历史上会混淆调试信息)留给读者。
  • @MatteoItalia 问题是可能与其他模块或库中的名称发生冲突。使用关键字可以避免这些冲突。
  • 不是真的......它只是将类型保存在一个单独的命名空间中,该命名空间仍然在所有包含的库之间共享,因此它有助于在类型和另一种符号之间发生冲突的不太可能的情况下.如果你有冲突的函数名称(这是通常发生的情况),你同样有麻烦。
  • @MatteoItalia 你在自相矛盾。如果您谈论的是单独的命名空间,那么您就是在确认我的说法。你只是不明白你自己在说什么。
  • 结构的命名空间,联合的命名空间和所有其他的命名空间;它们中的每一个都在您包含的所有库之间共享。我要说的只是它是一种错误的分离——你希望为每个库都有一个命名空间,而不是为每种实体都有一个命名空间(在不同的库之间仍然可能有冲突的名称)。
【解决方案2】:

使用当前安排,您可以同时拥有struct Book 和名为Book 的全局/本地符号,它不需要与struct Book 相关联。 struct stat 与名为 stat 的函数一起存在是 POSIX 中使用此功能的一个很好的例子。

显然,您可以像 C++ 那样自动化类型定义(从而失去在同一范围内可能不相关的 Bookstruct Book 的可能性),但我想不自动化它会使语法更整洁,因为如果你根本不使用typedefs,你就会得到一个基本无上下文的语法,而使用typedefs(显式或隐式)当前有效的typedefed类型的上下文必须由解析器维护。


就个人而言,我更喜欢自动化的typedefing,而不是全局范围与同名结构标签共存的可能性,所以我这样做:

#define Struct(Nm,...) typedef struct Nm Nm; struct Nm __VA_ARGS__
#define Union(Nm,...) typedef union Nm Nm; union Nm __VA_ARGS__
#define Enum(Nm,...) enum Nm __VA_ARGS__; typedef enum Nm Nm

Struct(Book,{
   char title[50];
   char author[50];
   char subject[100];
   int book_id;
});

(您可能希望将它与让您知道您正在处理结构/联合/枚举的命名约定一起使用(例如,_s,如book_s))。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    • 1970-01-01
    • 1970-01-01
    • 2011-07-06
    • 2013-09-21
    • 1970-01-01
    相关资源
    最近更新 更多