26

In this SO question I've encountered a very weird typedef:

struct Date {
    int day, month, year;
} typedef date_s;

I've always been seeing typedefs following this 'rule':

typedef <existing> <new>;

For example:

typedef unsigned long long ull;
typedef int kph; // speed
typedef void (*alpm_cb_log)(alpm_loglevel_t, const char *, va_list);

typedef int int_t;
typedef char char_t, *char_p, (*fp)(void);

The 4th one is taken from here, the 5th and 6th are from cppreference


And this is how I would typedef a struct:

typedef struct {
    int a, b, c;
} data;

// and then use it
data Something;

The question is how is this even possible to write such a typedef? It doesn't even make sense (at least to me).

clang doesn't give any errors or warnings, even with -Wall -Wextra.

Bonus question: should I advise the author of the question where this code could be found to avoid using such a typedef (because it's very unusual and may lead to confusion)?

Community
  • 1
  • 1
ForceBru
  • 43,482
  • 10
  • 63
  • 98
  • 5
    It is fine, though unusual. Much as int const i; –  May 01 '16 at 20:33
  • 4
    @piling I like `int const i` much more than `const int i`. It's less confusing when working with pointers, since you only have to follow one general rule: "Whatever precedes const is const". `int const* i;` is much more concise than `const int *i;`. – Leandros May 01 '16 at 20:43
  • The actual rule is that it is the same as declaring a variable, but putting `typedef` (almost) anywhere makes it declaring a type alias instead of a variable. People usually put it at the front for clarity – M.M May 01 '16 at 21:04

1 Answers1

31

It turns out that typedef can be placed after the existing type (in addition to before it). This little oddity, now obsolescent*, is caused by the way in which the C standard "bundles" typedefs with storage class specifiers, such as static and auto:

A declaration is defined as follows:

<declaration> ::=  {<declaration-specifier>}+ {<init-declarator>}*

This means that declaration specifiers can appear in any order. Now, declaration specifier is

<declaration-specifier> ::= <storage-class-specifier>
                          | <type-specifier>
                          | <type-qualifier>

And storage class specifier is

<storage-class-specifier> ::= auto
                        | register
                        | static
                        | extern
                        | typedef

The declaration of the struct's elements is a type specifier. Like typedef keyword, it is a declaration specifier. Since declaration specifiers can appear in any order, both placements of typedef (i.e., before and after the struct) are valid and identical to each other.

* N1570, 6.11.5: "The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature." Thanks, Keith Thompson, for a great comment!

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 10
    [N1570](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) 6.11.5: "The placement of a storage-class specifier other than at the beginning of the declaration specifiers in a declaration is an obsolescent feature." It's still perfectly legal, but a future version of the language might make it illegal. – Keith Thompson May 01 '16 at 20:51