2016-05-01 13 views
30

In this SO question ho incontrato un molto stranotypedef:Come è possibile questo typedef?

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

Ho sempre stato vedere typedef s seguendo questa 'regola':

typedef <existing> <new>; 

Ad esempio:

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); 

Il 4 ° è tratto da here, il 5 e 6 sono da cppreference


E this è come vorrei typedef un struct:

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

// and then use it 
data Something; 

La domanda è come è questo anche possibile scrivere tale typedef? Non ha nemmeno senso (almeno per me).

clang non fornisce alcun errore o avviso, anche con -Wall -Wextra.

Domanda bonus: dovrei consigliare l'autore della domanda in cui questo codice è stato trovato di evitare l'uso tale typedef (perché è molto insolito e può portare a confusione)?

+5

Va bene, anche se insolito. Proprio come int const i; –

+4

@piling Mi piace 'int const i' molto più di' const int i'. È meno confuso quando si lavora con i puntatori, dal momento che si deve solo seguire una regola generale: "Qualunque cosa precede const è const". 'int const * i;' è molto più conciso di 'const int * i;'. – Leandros

+0

La regola attuale è che è la stessa cosa che dichiarare una variabile, ma mettere "typedef' (quasi) ovunque lo rende dichiarando un alias di tipo invece di una variabile. La gente di solito la mette in primo piano per chiarezza –

risposta

32

Si scopre che typedef può essere inserito dopo il tipo esistente (oltre a prima). Questa piccola stranezza, ora obsoleto *, è causata dal modo in cui i C standard "pacchetti" typedef s con specificatori classe di memoria, come static e auto:

Un dichiarazione è definito come segue :

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

Ciò significa che gli specificatori di dichiarazione possono essere visualizzati in qualsiasi ordine. Ora, dichiarazione specificatore è

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

E classe di memorizzazione specificatore è

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

La dichiarazione di elementi s' il struct è un indicatore di tipo. Come la parola chiave typedef, è uno specificatore di dichiarazione. Poiché gli identificatori di dichiarazione possono essere visualizzati in qualsiasi ordine, entrambi i posizionamenti di typedef (vale a dire prima e dopo lo struct) sono validi e identici tra loro.

*N1570, 6.11.5: "Il posizionamento di un identificatore di classe di memoria diverso da quello all'inizio degli specificatori di dichiarazione in una dichiarazione è una funzione obsoleta." Grazie, Keith Thompson, per un grande commento!

+10

[N1570] (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) 6.11.5: "Il posizionamento di un archivio L'identificatore della classe diverso da quello iniziale degli specificatori di dichiarazione in una dichiarazione è una caratteristica obsoleta. " È ancora perfettamente legale, ma una versione futura della lingua potrebbe renderla illegale. –