2010-11-17 2 views
3
gcc 4.4.4 c89 

J'ai toujours fait ce qui suit lors de l'utilisation de structures pour cacher les éléments dans le fichier d'implémentation.révision de 2 méthodes différentes de typedef'ing une structure

fichier d'en-tête de port.h

struct port_tag; 
struct port_tag* open_ports(size_t port_id); 
void close_ports(struct port_tag *port); 

fichier d'implémentation de port.c

#include "port.h" 
typedef struct port_tag { 
    size_t port_id; 
} port_t; 

port_t* open_ports(size_t port_id) 
{ 
    port_t *port = malloc(sizeof *port); 
    if(port == NULL) { 
     return NULL; 
    } 
    port->port_id = port_id; 
    return port; 
} 

void close_ports(port_t *port) 
{ 
    if(port != NULL) { 
     free(port); 
    } 
} 

fichier pilote driver.c

#include "port.h" 
int main(void) 
{ 
    size_t i = 0; 
    struct port_tag *port = NULL; 

    for(i = 0; i < 5; i++) { 
     port = open_ports(i); 

     if(port == NULL) { 
      fprintf(stderr, "Port [ %d ] failed to open\n", i); 
     } 
     close_ports(port); 
    } 
    return 0; 
} 

Dans le code ci-dessus, il est clair que la balise le nom est port_tag et le nom réel de type typedef'ed est port_t.

Cependant, je suis en train de réorganiser un code. Et j'ai trouvé qu'ils ont utilisé une méthode différente, que je n'avais jamais vue auparavant. J'ai quelques questions sur leur méthode.

fichier d'en-tête de channel.h

typedef struct channel_t channel_t; 
channel_t* open_channels(size_t channel_id); 
void close_channels(channel_t *channel); 

fichier d'implémentation de channel.c

#include "channel.h" 
struct channel_t { 
    size_t channel_id; 
}; 

channel_t* open_channels(size_t channel_id) 
{ 
    channel_t *channel = malloc(sizeof *channel); 

    if(channel == NULL) { 
     return NULL; 
    } 
    channel->channel_id = channel_id; 
    return channel; 
} 

void close_channels(channel_t *channel) 
{ 
    if(channel != NULL) { 
     free(channel); 
    } 
} 

fichier pilote driver.c

#include "channel.h" 
int main(void) 
{ 
    size_t i = 0; 
    channel_t *channel = NULL; 

    for(i = 0; i < 5; i++) { 
     channel = open_channels(i); 

     if(channel == NULL) { 
      fprintf(stderr, "Channel [ %zu ] failed to open\n", i); 
     } 

     close_channels(channel); 
    } 
    return 0; 
} 

1) Quand ils ont déclaré typedef struct qui est le nom de l'étiquette ou le nom de la struct lui-même?

typedef struct channel_t channel_t; 

2) Dans le fichier d'implémentation, le nom de la structure ne doit-il pas suivre la dernière accolade?

struct channel_t <-- tag name { 
    size_t channel_id; 
} <-- itsn't this the name of the typedef'ed struct; 

Un grand merci pour tous les conseils,

+1

+1 Pour une question intéressante et méticuleusement présentée. J'ai appris quelque chose car j'expose toujours l'implémentation de la structure au code client, inutilement comme il s'avère. –

Répondre

4

1.   Le type struct est struct channel_t, et le nouveau typedef est channel_t.

Cela signifie qu'il peut maintenant être utilisé comme:

channel_t some_instance; 

2.   Ils créent un typedef ailleurs, pas ici. Donc tout:

struct channel_t { 
    size_t channel_id; 
}; 

fait est de définir un type struct avec étiquette channel_t. Aucun typedef n'est requis lors de la définition d'un struct. Il peut être utilisé comme, par exemple .: Comme vous l'avez vu

struct channel_t some_instance; 

, les deux syntaxes sont essentiellement équivalentes dans ce cas.

+1

+1, quelques commentaires supplémentaires: définir un 'struct' et typedef avec le même nom que la balise struct inhibe que quelqu'un d'autre peut accidentellement déclarer un autre identifiant global avec le même nom. Cela évite la confusion et les accidents. Pour (2) non seulement le 'typedef' n'est pas nécessaire ici, il n'est même pas autorisé. Autre que pour C++ 'typedef's peut apparaître qu'une seule fois, même si elles se répètent exactement. –

+0

@Jens, bon point. En ce qui concerne (2), je voulais dire que les typedefs ne sont pas obligatoires en général, ce qui, je suppose, va sans dire. –

2
typedef struct channel_t channel_t; 

Cela signifie qu'une structure appelée "struct channel_t" peut également être appelée en utilisant le nom "channel_t". Il n'y a pas de conflit, puisque le nom du premier type est "struct channel_t" et pas seulement "channel_t".Comme pour (2), cela ne fait que définir la structure. La ligne typedef est juste un typedef, elle ne définit pas la structure. Ce modèle (aucune définition de structure dans l'en-tête, définition de structure dans la source) est généralement utilisé lorsque vous voulez que l'API fournisse le type sécurité (au lieu d'utiliser "void *") sans exposer les composants internes de la structure.

Questions connexes