简体   繁体   中英

C : Can't understand how 2nd and 3rd method of declaration of structure and variables of this type are valid?

Here are three methods given in my book:-

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;

In 2nd method,there is a confusion why the closing brace in structure type declaration is not followed by a semicolon?

The 3rd method doesn't make any sense to me because we don't even declared the name of the structure.

So, How these two methods are valid?

At the time a struct is defined, you can also define one or more instances of that struct. This is what is happening in both the 2nd and the 3rd examples.

The difference between the two is that one declares three variables of type struct book at the time that type is defined, while the other declares three variables whose type is an anonymous struct. In the latter case, that means that no other variables of that type may be defined since the struct has no name and does not have an associated typedef .

The whole construct of

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

is itself a type . So you can use it in variable declarations in the same way you use other types. They are all of the form

<type> <identifier>;

with optionally more identifiers to declare multiple variables at once.

By example:

struct {int x; char y;} bar;

is a valid variable declaration, just as

int bar;

is. Remember newlines don't have any syntactical meaning in C.


With a struct , you can give it a name (called struct tag ), like this:

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

If you do this, you can later use the same struct type by just writing

struct foo

instead of repeating all its fields. That's in fact the most common usage.

TL/DR - C declaration syntax allows all three methods .

Have patience, this is going to take a while.

Let's start with the syntax for a declaration:

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

The opt subscript means that the item is optional; IOW, a sequence of declaration specifiers may be followed by a sequence of declarators (or not), a type specifier may be followed by more declaration specifiers (or not), etc.

We also have the following constraint :

A declaration other than a static_assert declaration shall declare at least a declarator (other than the parameters of a function or the members of a structure or union), a tag, or the members of an enumeration.

C 2011 Online Draft, 6.7

Lovely. What does all that mean?

Basically, a declaration in C has two main parts - a sequence of declaration specifiers (which may include storage class specifiers like static and auto , type specifiers like int , double , char , struct foo , type qualifiers like const , etc.) and an optional sequence of declarators (basically, variable or function names), each of which may be initialized. For example, in the declaration

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

our declaration specifiers are static const int , our declarator is *foo[N] , and our initializer is { &bar, &blah, ... } .

What we're interested in for the purpose of your question is the type-specifier , and specifically a 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

The struct-or-union-specifier has two forms - one where you specify the contents of the struct, and one where you do not.

The identifier is the tag name of the structure or union; it's how you can refer to that specific type later on (either as part of another declaration, or part of a sizeof expression, etc).

Note that in the first case, where you're specifying the members of the structure type, the tag name is optional - it's perfectly legal to write a declaration like

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

The struct definition itself is a type specifier, just like int or double , etc.

However, without a tag name, you cannot refer to this same structure type in future declarations. You can certainly repeat the definition for another variable:

struct { int a; int b; } y;

but the types of x and y will be distinct - the compiler considers each struct definition to be a different type, even though they have the same contents.

Now, remember from the general declaration syntax above, the list of declarators in a declaration is optional . This is what allows us to declare a structure with just a tag name (although per the constraint above, you must include the tag name if you are not declaring a variable of this type):


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

We've defined the struct type and given it the tag name foo ; we can declare objects of this type as

struct foo x;
struct foo y;

Because from the syntax above:

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

This time, x and y are considered to be the same type.

We can also declare a variable at the same time we define the struct:

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

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

The first declaration creates the struct foo type and declares x to be a variable of that type. The second declaration uses the previously defined struct foo type to declare a variable y .

Basically, C declaration syntax, especially with respect to structures, unions, and enums, is fairly flexible, and all of the methods listed in your book are equally valid.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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