ant2009
ant2009

Reputation: 22486

review of 2 different methods of typedef'ing a struct

gcc 4.4.4 c89

I have always done the following when using structs to hide the elements in the implementation file.

port.h header file

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

port.c implementation file

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

driver.c driver file

#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;
}

In the above code it is clear that the tag name is port_tag and the actual typedef'ed name is port_t.

However, I am re-engineering some one code. And I have found they have used a different method, that I have never seen before. I have a few questions about their method.

channel.h header file

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

channel.c implementation file

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

driver.c driver file

#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) When they have declared the typedef'ed struct which is the tag name or the name of the struct itself?

typedef struct channel_t channel_t;

2) In the implementation file shouldn't the name of the struct follow the last curly brace?

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

Many thanks for any advice,

Upvotes: 3

Views: 379

Answers (2)

Matthew Flaschen
Matthew Flaschen

Reputation: 284796

1. The struct type is struct channel_t, and the new typedef is channel_t.

That means it can now be used as:

channel_t some_instance;

2. They're creating a typedef elsewhere, not here. So all:

struct channel_t {
    size_t channel_id;
};

does is define a struct type with tag channel_t. No typedef is required when defining a struct. It can be used as, e.g.:

struct channel_t some_instance;

As you've seen, the two syntaxes are basically equivalent in this case.

Upvotes: 4

vanza
vanza

Reputation: 9903

typedef struct channel_t channel_t;

That means that a struct called "struct channel_t" can also be referred to by using the name "channel_t". There's no conflict, since the name of the former type is "struct channel_t" not just "channel_t".

As for (2), that's just defining the struct. The typedef line is just a typedef, it doesn't define the struct. This pattern (no struct definition in header, struct definition in source) is generally used when you just want the API to provide type safety (instead of using "void *"), without exposing the internals of the struct.

Upvotes: 2

Related Questions