What is the difference between these two structure declarations?

Viewed 3709

I am confused about these two structures from different tutorials:

typedef struct complex {
    float real;
    float imag;
} COMPLEX;

typedef struct {
    float real;
    float imag;
} COMPLEX;

COMPLEX c1;

Are they both correct? Why? and is it necessary to add the lowercase of complex before struct? What is general situation?

8 Answers

With the first you can use either the type-alias COMPLEX or struct complex.

With the second you have an anonymous structure which can only be used with the type-alias COMPLEX.

With that said, in C++ any structure name is also a type-name and can be used as a type directly:

struct complex { ... };
complex c1;
typedef struct complex{
    float  real;
    float imag;
}COMPLEX;

This is a struct complex which has been typedef'ed to COMPLEX. You can now use both struct complex c1; and COMPLEX c1;. As you tagged this question C++, you can also use complex c1; as the struct (and thus, the typedef to avoid it) is not necessary in C++.

typedef struct {
    float  real;
    float imag;
}COMPLEX;

This is an unnamed struct, typedef'ed to COMPLEX. You can now use COMPLEX c1;.

So far for the difference between these two (C) constructs.

As you tagged this question C++, the correct thing to do would be to use the features of the C++ header <complex>:

std::complex< float > c1;

For starters there is no anonymous structure as others have written in their answers to your question. There is an unnamed structure (a structure without a tag name) that has the alias name COMPLEX

typedef struct {
    float real;
    float imag;
} COMPLEX;

In C++ the term unnamed class/structure is documented like (the C++ 14 Standard, 9 Classes)

A class-specifier whose class-head omits the class-head-name defines an unnamed class.

As for the notion anonymous structure then it is defined in C the following way (6.7.2.1 Structure and union specifiers, p.#1)

13 An unnamed member of structure type with no tag is called an anonymous structure; an unnamed member of union type with no tag is called an anonymous union. The members of an anonymous structure or union are considered to be members of the containing structure or union. This applies recursively if the containing structure or union is also anonymous.

Here is an example of an anonymous structure

struct A
{
    struct { int x; int y; };  // <== anonymous structure
    int z;
};

Bear in mind that in C++ opposite to C there is no such a notion as anonymous structure. In C++ there is only the notion of anonymous union.

As for your question

Are they both correct? Why? and is it necessary to add the lowercase of complex before struct? What is general situation?

then the both typedef declarations are correct. And there is no need to use exactly lower-case name complex as the structure tag. You may use also upper-case name COMPLEX as the structure tag.

typedef struct COMPLEX {
    float real;
    float imag;
} COMPLEX;

In this structure declaration

typedef struct {
    float  real;
    float imag;
}COMPLEX;

there is declared a structure without a tag name. So you can refer it only by means of its alias name COMPLEX.

In C structure tag names have their own name space that do not conflict with identifier names in other name spaces.

From the C Standard (6.2.3 Name spaces of identifiers)

1 If more than one declaration of a particular identifier is visible at any point in a translation unit, the syntactic context disambiguates uses that refer to different entities. Thus, there are separate name spaces for various categories of identifiers, as follows:

— the tags of structures, unions, and enumerations (disambiguated by following any32) of the keywords struct, union, or enum);

For example consider the following program.

#include <stdio.h>

typedef struct {
    float  real;
    float imag;
} COMPLEX;

int main(void) 
{
    int COMPLEX;
    COMPLEX c = { 0.0f, 0.0f };
    
    return 0;
}

The compiler will issue an error because the declaration of the local variable COMPLEX hides the alias name of the unnamed structure declared in the file scope.

However if you will write

#include <stdio.h>

typedef struct COMPLEX {
    float  real;
    float imag;
} COMPLEX;

int main(void) 
{
    int COMPLEX;
    struct  COMPLEX c = { 0.0f, 0.0f };
    
    return 0;
}

then the name COMPLEX of the local variable will not conflict with the tag name COMPLEX of the structure. The C compiler can only issue a message that declared variables are not used.

Another important difference is that sometimes you need to refer to the declared structure specifier within the structure definition itself.

For example if you want to declare a singly-linked list in C you need to write

typedef struct Node
{
    int data,
    struct Node *next;
} Node;

Without the tag name like

typedef struct 
{
    int data,
    struct Node *next;
} Node;

the compiler considers this structure definition as declarations of two different type specifiers: unnamed structure with the alias name Node and another structure with the tag name Node. These types are not compatible.

As for C++ then you may use the name of a structure tag without specifying the keyword struct

For example

struct complex{
    float  real;
    float imag;
};

struct complex c1;
complex c2;

Also you can refer the structure specifier within its definition without using the keyword struct because (the C++ 15 Standard, 9 Classes)

2 A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.

For example

struct Node
{
    int data,
    Node *next;
};

But again a declaration of a variable or a function can hide a declaration of a structure. In this case you need to use the keyword struct. Such using of a name with the keyword struct is called in C++ as elaborated type specifier.

For example

struct complex{
    float  real;
    float imag;
};

int complex;
struct complex c;

Without specifying the keyword struct the compiler will issue an error because the declaration of the integer variable hides the declaration of the structure.

Pay attention to that many programmers do not even know that the typedef in C and C++ can be also rewritten like

struct COMPLEX {
    float  real;
    float imag;
} typedef COMPLEX;

This is really because the type system changed subtly between C and C++. User defined structures (and enums) in C had "tags", which were treated as different from types.

struct Tag {/*some members*/};
typedef struct Tag Type; /* Tag and Type can be the same name */

This way of working is still supported as your example shows, but C++ added a new rule, that says that structure tags are always types as well. Thus, viewed from a C view-point it's as if the C++ compiler adds the typedef for you. Thus in C++ you no longer need to say "struct" before declaring variable of your structure type.

So yes, both ways are "correct", one is the old C way, and will work in both C and C++, the other is the native C++ way, and will not compile in C. It's possible your example needed C compatibility for some of the code but not all.

If you need C-compatibility you should use the pattern above, but it is not common practice to use it for native C++ code.

struct definition is as below:

struct type_name {
       member_type1 member_name1;
       member_type2 member_name2;
       .
       .
                } object_names;

you use one name for struct name and object name. you can use object in side of structure definition without declare a name for struct

In C++, there is only a subtle difference. It's a holdover from C, in which it makes a difference.

The C language standard (C89 §3.1.2.3, C99 §6.2.3, and C11 §6.2.3) mandates separate namespaces for different categories of identifiers, including tag identifiers (for struct/union/enum) and ordinary identifiers (for typedef and other identifiers).

If you just said:

struct Foo { ... };
Foo x;

you would get a compiler error, because Foo is only defined in the tag namespace.

You'd have to declare it as:

struct Foo x;

Any time you want to refer to a Foo, you'd always have to call it a struct Foo. This gets annoying fast, so you can add a typedef:

struct Foo { ... };
typedef struct Foo Foo;

Now struct Foo (in the tag namespace) and just plain Foo (in the ordinary identifier namespace) both refer to the same thing, and you can freely declare objects of type Foo without the struct keyword.

The construct:

typedef struct Foo { ... } Foo;

is just an abbreviation for the declaration and typedef.

Finally,

typedef struct { ... } Foo;

declares an anonymous structure and creates a typedef for it. Thus, with this construct, it doesn't have a name in the tag namespace, only a name in the typedef namespace. This means it also cannot be forward-declared. If you want to make a forward declaration, you have to give it a name in the tag namespace.

In C++, all struct/union/enum/class declarations act like they are implicitly typedef'ed, as long as the name is not hidden by another declaration with the same name.

There is nothing like C/C++ language.

In C.

   typedef struct complex {
        float real;
        float imag;
    } COMPLEX;

    COMPLEX c1;
    struct complex c2;

Aliases struct complex to type COMPLEX

   typedef struct{
        float real;
        float imag;
    } COMPLEX;

    COMPLEX c1;

Aliases tagless structure to type COMPLEX

What is the practical difference?

As you see using the first one you can define new objects using the new type COMPLEX and struct complex.

The secon type decvlaration allows only definitions using COMPLEX type.

Think of "namespaces" here: struct names live in their own namespace.

struct complex {
    float real;
    float imag;
};

struct complex myvar; // in C and C++
complex myvar // only in C++!

C++ also resolves struct-tags (if not otherwise possible), where C does not. typedef defines an alias for a typename, i.e.

typedef struct complex COMPLEX;

will define a new name COMPLEX which is a stand-in for struct complex.

This declaration

typedef struct complex {
    float real;
    float imag;
} COMPLEX;

is shorthand for

struct complex {
    float real;
    float imag;
};
typedef struct complex COMPLEX;

You can also omit the struct-tag altogether

typedef struct {
    float real;
    float imag;
} COMPLEX;

just as in

struct {
    float real;
    float imag;
} myvar;

which defines a variable myvar with an unnamed struct type.

Related