6

Is the following, at file scope, a type declaration or an unnamed variable?

struct student_s {
    char* name;
    int age;
    double height;
    struct student_s* next;   
};

If it is a type definition, then what is the difference with:

typedef struct student_s {
    char* name;
    int age;
    double height;
    struct student_s* next;   
};

?

(Background: see my answer at Changing a variable from global to local - C, where I believe the first introduces an unnamed variable that is then optimized away by the compiler.)

Note: the question has been flagged as a possible duplicate of In what scope is a struct member identifier put? but I believe I am not asking a question about the scope of the members but about what the declarations actually create. However. answers to Difference between 'struct' and 'typedef struct' in C++? do explain my question.

Community
  • 1
  • 1
Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • Why do you think it would define an unnamed variable, rather than no variable ? Are you expecting an unnamed type alias from the second snippet ? – Quentin Aug 07 '15 at 12:35
  • http://stackoverflow.com/questions/5276270/in-what-scope-is-a-struct-member-identifier-put – smali Aug 07 '15 at 12:36
  • 1
    You could take a look at [this thread](http://stackoverflow.com/questions/1675351/typedef-struct-vs-struct-definitions?rq=1) as well for more infos – Peut22 Aug 07 '15 at 12:38
  • The link you posted points to an answer that is not yours. You wanted this instead: http://stackoverflow.com/a/31874396/2793118 The former is a type definition, the latter is invalid because there is no name argument for the `typedef`. – Filipe Gonçalves Aug 07 '15 at 12:42
  • 1
    The difference: the first is valid C, the second is not. – too honest for this site Aug 07 '15 at 14:01

6 Answers6

7

As per the C standard, a structure declaration in the form like

struct student_s {
    char* name;
    int age;
    double height;
    struct student_s* next;   
};

is the declaration of a type. Quoting C11, chapter §6.7.2.1

The presence of a struct-declaration-list in a struct-or-union-specifier declares a new type, within a translation unit. The struct-declaration-list is a sequence of declarations for the members of the structure or union. [...]

C standard does not mandate creating a variable (either named or unnamed) for that type.

In your second snippet, you actually (try to) typedef to nothing. However, if you change your snippet to the form of

typedef struct {
         //.....members
} student_s ;

you'll be creating a type student_s (typedef to an unnamed structure type) which you can use later.

FWIW, we never talked about a variable being created here, anyways. It's all about types.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • In the last example, can the `next` pointer be declared like that, when the struct is anonymous and the typedef not yet complete? – Useless Aug 07 '15 at 12:47
  • @Useless Yes, I (_we_ ?) missed the case of having the member variable. Not trying to defend the mistake (corrected now), but that is not in direct scope of the question, IMHO. :-) – Sourav Ghosh Aug 07 '15 at 13:07
  • 1
    Agreed, I didn't spot it until about the 3rd time I read it :) – Useless Aug 07 '15 at 13:17
3

First declaration declares a type. After that declaration, the type struct student_s is known, and you can declare variables of that type or pointer to it :

struct student_s student1;
struct student_s *pStudent;

The second declaration is weird even if is compiles. The common usage would be :

typedef struct {
    char* name;
    int age;
    double height;
    struct student_s* next;   
} studend_t;

which declares an alias student_t to an anonymous struct. It can then be used directly :

student_t student1;
student_t *pStudent;

BUT THE SECOND EXAMPLE DOES COMPILE (even with a warning) AND IS THE SAME AS FIRST ONE !

What it really does is to declare a void alias to struct student_s. The typedef is ignored and produces a warning : typedef requires a name, but as a side effect, the struct is declared, exactly as it was in first example.

So the true answer to the actual question is THERE ARE NO DIFFERENCES except for a warning.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • Except you can't declare that `next` pointer to an anonymous struct, as per Sourav's answer. – Useless Aug 07 '15 at 13:07
  • While the second declaration doesn't do what the OP thinks it does, I don't think it is ill-formed. This is perhaps a good language lawyer question. – David Hammen Aug 07 '15 at 13:30
  • @DavidHammen : I tried it and was surprised that it compiled. See my edit. – Serge Ballesta Aug 07 '15 at 13:55
  • I asked about the legality of this as a separate question, http://stackoverflow.com/questions/31879335/legality-of-typedef-struct-foo-int-bar Even if it is illegal, the compiler has done it's job by issuing a diagnostic. The standard doesn't say that the compiler shall not produce object code in the face of ill-formed code. Multiple compilers produce object code after I inserted a meaningless `static;` at file scope in some source file. They did issue a diagnostic. – David Hammen Aug 07 '15 at 14:01
2

Both are type definitions. The second one is one incomplete. It doesn't supply a name as the the argument of typedef. Much better is to use

typedef struct student_s {
    char* name;
    int age;
    double height;
    struct student_s* next;   
} student;


Regarding the legality of

typedef struct student_s {
    char* name;
    int age;
    double height;
    struct student_s* next;   
};

I've asked that as a separate question, Legality of `typedef struct foo {int bar};`

Community
  • 1
  • 1
David Hammen
  • 32,454
  • 9
  • 60
  • 108
1

It's a type, and you can't have an anonymous instance of a struct. For comparison, this declares both the type struct_type and an instance struct_instance of that type:

struct struct_type {
    /* blah */
} struct_instance;

If you wanted to declare another instance in isolation (from the type decl) you'd use

struct struct_type another_instance;

The use of typedef - if done correctly, unlike your example - just allows you to give the type another name which doesn't require the struct keyword to declare an instance:

typedef struct_type MyStruct;
MyStruct yet_another_instance;

or equivalently

typedef struct struct_type {
    /* blah */
} MyStruct;

omitting the name (struct_type) gives you an anonymous struct type which can only referred to by its typedef'd name.


Note 1

Since your original struct contains a next pointer to its own type, that type must have a name at the point the member is declared. So, you cannot declare an anonymous struct with a self-typed pointer. If you give your anonymous struct type a name with typedef, that name doesn't exist until after the member declaration, so can't be used there.

typedef struct /*S*/ {
    struct S *next; /* T doesn't exist yet, so without S, you can't declare this */
} T;

Note 2

You can declare an anonymous instance of an anonymous union, as a member:

struct S {
    union {
        int i;
        unsigned u;
    };
};

struct S s;
s.i = -1;
printf("%x\n", s.u);

but that's a very special case. I took the remark about this out of the main argument, in case it was misleading.

Useless
  • 64,155
  • 6
  • 88
  • 132
1
struct A { ... }

creates struct 'A' visible in struct namespace (which has nothing common with C++ namespaces). So, to access struct you have to use struct keyword;

struct A a;

When defined with typedef struct

typedef struct A { ... } B;

becomes visible and bound to B, and you can easily create struct like common variable of type B

B a;

Please, correct me someone, if I am wrong.

Ivan Ivanov
  • 2,076
  • 16
  • 33
0

The difference is that with the first example, you have to declare a new variable like this: struct student_s variable;, however with the second example, you may simply do student_s variable;.

pelya
  • 4,326
  • 2
  • 24
  • 23
  • 3
    Not with this example. No typedef name is defined. – David Hammen Aug 07 '15 at 12:38
  • Actually, `gcc` does compile it, but gives the warning `warning: useless storage class specifier in empty declaration` – dbush Aug 07 '15 at 12:43
  • @dbush - That's because a declaration has the form *declaration-specifiers init-declarator-list* opt ; Here `typedef` acts as a *storage_class_specifier*. The standard doesn't say that something has to be provided as the name to be typedefed. It does say that at least one name shall be introduced, and that is happening. – David Hammen Aug 07 '15 at 13:01
  • @pelya - Suppose you add a superfluous `typedef int;` at file scope somewhere in your code. The standard says that a diagnostic must be issued as this is illegal code. The standard is moot on the consequences of that diagnostic. The standard does not say anything about fatal diagnostics versus mere warnings. The compiler can still generate an object file. This does compile (in the sense of producing an object file) with multiple versions of clang and gcc. – David Hammen Aug 07 '15 at 13:28