0

以下是我书中给出的三种方法:-

1)

struct book
{   char name;
    float price;
    int pages;

};

struct book b1; b2; b3;

2)

  struct book
{
   char name;
   float price;
   int pages;
}  
  b1, b2, b3;   

3)

struct
{
  char name;
  float price;
  int pages;
} b1, b2, b3;

在第二种方法中,为什么结构类型声明中的右大括号后面没有分号?

第三种方法对我来说没有任何意义,因为我们甚至没有声明结构的名称。

那么,这两种方法如何有效呢?

4

3 回答 3

2

TL/DR-C 声明语法允许所有三种方法

有耐心,这将需要一段时间。

让我们从声明的语法开始:

declaration:
    declaration-specifiers init-declarator-listopt ;
    static_assert-declaration

declaration-specifiers:
    storage-class-specifier declaration-specifiersopt
    type-specifier          declaration-specifiersopt
    type-qualifier          declaration-specifiersopt
    function-specifier      declaration-specifiersopt
    alignment-specifier     declaration-specifiersopt

init-declarator-list:
    init-declarator
    init-declarator-list , init-declarator

init-declarator:
    declarator
    declarator = initializer

opt标表示该项是可选的;IOW,声明说明符序列后面可以跟一系列声明符(或不跟),类型说明符后面可能跟更多声明说明符(或不跟),等等。

我们还有以下约束

除了 static_assert 声明之外的声明应至少声明一个声明符(函数的参数或结构或联合的成员除外)、标签或枚举的成员。

C 2011 在线草案,6.7

迷人的。这一切意味着什么?

基本上,C 中的声明有两个主要部分 -声明说明符序列(可能包括存储类说明符staticauto,类型说明符,如,,,,int类型限定符,等)和可选的声明符序列(基本上,变量或函数名),每个都可以被初始化。例如,在声明中doublecharstruct fooconst

static const int *foo[N] = { &bar, &blah, ... };

我们的声明说明符static const int,我们的声明符是,*foo[N]我们的初始化程序{ &bar, &blah, ... }

对于您的问题,我们感兴趣的是type-specifier,特别是struct-or-union-specifier

type-specifier:
    void
    char
    short
    int
    long
    float
    double
    signed
    unsigned
    _Bool
    _Complex
    atomic-type-specifier
    struct-or-union-specifier
    enum-specifier
    typedef-name

struct-or-union-specifier:
    struct-or-union identifieropt { struct-declaration-list }
    struct-or-union identifier

struct-or-union-specifier两种形式——一种是你指定结构的内容,另一种是你不指定。

identifier是结构或联合的标记名称;这是您稍后可以引用该特定类型的方式(作为另一个声明的一部分或sizeof表达式的一部分等)。

请注意,在第一种情况下,您指定结构类型的成员,标签名称是可选的 - 编写如下声明是完全合法的

struct { int a; int b; } x;
|                      | |
+---------+------------+ |
          |              V
          V          declarator
    type-specifier

结构定义本身是一个类型说明符,就像intordouble等​​一样。

但是,如果没有标记名称,则不能在以后的声明中引用相同的结构类型。您当然可以重复另一个变量的定义:

struct { int a; int b; } y;

但是 和 的类型xy不同的——编译器认为每个struct定义都是不同的类型,即使它们具有相同的内容。

现在,请记住上面的一般声明语法,声明中的声明符列表是可选的。这就是允许我们仅使用标签名称声明结构的原因(尽管根据上面的约束,如果您不声明此类型的变量,则必须包含标签名称):


struct foo { int a; int b; };
|                          |
+-----------+--------------+
            |
            V
      type-specifier

我们已经定义了结构类型并给了它标签名称foo;我们可以将这种类型的对象声明为

struct foo x;
struct foo y;

因为从上面的语法:

struct foo x;
|        |
+---+----+
    |
    V
type-specifier

这一次,xy被认为是同一类型。

我们也可以在定义结构体的同时声明一个变量:

struct foo { int a; int b; } x;
|                          |
+----------+---------------+
           |
           V
     type-specifier

struct foo y; | | +----+---+ | V type-specifier

第一个声明创建struct foo类型并声明为该类型x的变量。第二个声明使用先前定义的struct foo类型来声明一个变量y

基本上,C 声明语法,尤其是关于结构、联合和枚举的声明语法相当灵活,并且您书中列出的所有方法都同样有效。

于 2018-04-24T20:47:47.850 回答
2

整个构造

struct {
    int field1;
    char field2;
    // ...
}

本身就是一种类型。因此,您可以像使用其他类型一样在变量声明中使用它。它们都是形式

<type> <identifier>;

可以选择使用更多标识符来一次声明多个变量。

举例:

struct {int x; char y;} bar;

是一个有效的变量声明,就像

int bar;

是。请记住,换行符在 C 中没有任何语法意义。


使用 a struct,您可以给它一个名称(称为struct tag),如下所示:

struct foo {
    int field1;
    char field2;
    // ...
};

如果你这样做,你以后可以通过编写来使用相同的结构类型

struct foo

而不是重复其所有字段。这实际上是最常见的用法。

于 2018-04-24T16:53:27.017 回答
2

struct定义 a 时,您还可以定义该结构的一个或多个实例。这就是第二个和第三个例子中发生的事情。

两者的区别在于,一个struct book在定义类型时声明了三个类型的变量,而另一个声明了三个类型为匿名结构的变量。在后一种情况下,这意味着不能定义该类型的其他变量,因为该结构没有名称并且没有关联的typedef.

于 2018-04-24T16:52:12.200 回答