Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is 'forward declaration' and the difference between 'typedef struct X' and 'struct X'?

Tags:

c

struct

typedef

I am a beginner in C programming and I know the difference between struct type declaration and typedef struct declaration. I came across to know an answer saying that if we define a struct like:

typedef struct { 
    some members;
} struct_name;

Then it will be like providing an alias to an anonymous struct (as it is not having a tag name). So it can't be used for forward declaration. I don't know what the forward declaration means.

Also, I wanted to know that for the following code:

typedef struct NAME { 
    some members;
} struct_alias;

Is there any difference between NAME and struct_alias? Or are both equal as struct_alias is an alias of struct NAME ?

Furthermore, can we declare a variable of type struct NAME like these:

struct_alias variable1;

and/or like:

struct NAME variable2;

or like:

NAME variable3; 
like image 682
r_goyal Avatar asked Sep 06 '13 12:09

r_goyal


People also ask

What is the difference between typedef struct and struct declaration?

In C++, there is no difference between 'struct' and 'typedef struct' because, in C++, all struct/union/enum/class declarations act like they are implicitly typedef'ed, as long as the name is not hidden by another declaration with the same name.

What is forward declaration of struct?

A struct (without a typedef) often needs to (or should) be with the keyword struct when used. struct A; // forward declaration void function( struct A *a ); // using the 'incomplete' type only as pointer. If you typedef your struct you can leave out the struct keyword.

What is forward declaration in C?

In computer programming, a forward declaration is a declaration of an identifier (denoting an entity such as a type, a variable, a constant, or a function) for which the programmer has not yet given a complete definition.

Can I forward declare a typedef?

But you can't forward declare a typedef. Instead you have to redeclare the whole thing like so: typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value; Ah, but I don't have any of those classes declared either.


5 Answers

struct forward declarations can be useful when you need to have looping struct declarations. Example:

struct a {
    struct b * b_pointer;
    int c;
};

struct b {
    struct a * a_pointer;
    void * d;
};

When struct a is declared it doesn't know the specs of struct b yet, but you can forward reference it.

When you typedef an anonymous struct then the compiler won't allow you to use it's name before the typedef.

This is illegal:

struct a {
    b * b_pointer;
    int c;
};

typedef struct {
    struct a * a_pointer;
    void * d;
} b;

// struct b was never declared or defined

This though is legal:

struct a {
    struct b * b_pointer;
    int c;
};

typedef struct b {
    struct a * a_pointer;
    void * d;
} b;

// struct b is defined and has an alias type called b

So is this:

typedef struct b b;
// the type b referes to a yet undefined type struct b

struct a {
    b * struct_b_pointer;
    int c;
};

struct b {
    struct a * a_pointer;
    void * d;
};

And this (only in C, illegal in C++):

typedef int b;

struct a {
    struct b * struct_b_pointer;
    b b_integer_type;
    int c;
};

struct b {
    struct a * a_pointer;
    void * d;
};

// struct b and b are two different types all together. Note: this is not allowed in C++
like image 178
Sergey L. Avatar answered Sep 30 '22 17:09

Sergey L.


Forward declaration is a promise to define something that you make to a compiler at the point where the definition cannot be made. The compiler can use your word to interpret other declarations that it would not be able to interpret otherwise.

A common example is a struct designed to be a node in a linked list: you need to put a pointer to a node into the struct, but the compiler would not let you do it without either a forward declaration or a tag:

// Forward declaration
struct element;
typedef struct {
    int value;
    // Use of the forward declaration
    struct element *next;
} element; // Complete definition

and so it cant be used for forward declaration

I think that author's point was that giving your struct a tag would be equivalent to a forward declaration:

typedef struct element {
    int value;
    // No need for a forward declaration here
    struct element *next;
} element;
like image 30
Sergey Kalinichenko Avatar answered Oct 03 '22 17:10

Sergey Kalinichenko


Forward declaration is a declaration preceeding an actual definition, usually for the purpose of being able to reference the declared type when the definition is not available. Of course, not everything may be done with the declared-not-defined structure, but in certain context it is possible to use it. Such type is called incomplete, and there are a number of restrictions on its usage. For example:

struct X; // forward declaration

void f(struct X*) { }  // usage of the declared, undefined structure

// void f(struct X) { }         // ILLEGAL
// struct X x;                  // ILLEGAL
// int n =sizeof(struct X);     // ILLEGAL

// later, or somewhere else altogether
struct X { /* ... */ };

This can be useful e.g. to break circular dependencies, or cut down the compilation time, as the definitions are usually significantly larger, and so more resources are required to parse it.

In your example, struct NAME and struct_alias are indeed equivalent.

struct_alias variable1;
struct NAME variable2;

are correct;

NAME variable3;

is not, as in C the struct keyword is required.

like image 31
Marcin Łoś Avatar answered Oct 01 '22 17:10

Marcin Łoś


struct_alias and struct NAME are same ,struct_alias is an alias to struct NAME

These both are same and allowed

struct_alias variable1;  

struct NAME variable1; 

this is illegal

NAME variable3;   

See this article on Forward declaration

like image 20
Gangadhar Avatar answered Sep 30 '22 17:09

Gangadhar


As others stated before, a forward declaration in C/C++ is the declaration of something with the actual definition unavailable. Its a declaration telling the compiler "there is a data type ABC".

Lets pretend this is a header for some key/value store my_dict.h :

...
struct my_dict_t;
struct my_dict_t* create();

char* get_value(const struct my_dict_t* dict, const char* name);
char* insert(struct my_dict_t* dict, const char* name, char* value);
void destroy(struct my_dict_t* dict);
...

You dont know anything about my_dict_t, but actually, for using the store you dont need to know:

#include "my_dict.h"
...
struct my_dict_t* dict = create();
if(0 != insert(dict, "AnEntry", strdup("AValue"))) {
    ...
}
...

The reason for this is: You are only using POINTERS to the data structure.

POINTERS are just numbers, and for dealing with them you dont need to know what they are pointing at.

This will only matter if you try to actually access them, like

struct my_dict_t* dict = create();
printf("%s\n", dict->value);  /* Impossible if only a forward decl is available */

So, for implementing the functions, you require an actual definition of my_struct_t. You might do this in the source file my_dict.c like so:

#include "my_dict.h"

struct my_dict_t {
    char* value;
    const char* name;
    struct my_dict_t* next;
}

struct my_dict_t* create() {
    return calloc(1, sizeof(struct my_dict_t));
}

This is handy for several situations, like

  • For resolving circular type dependencies, like Sergei L. explained.
  • For encapsulation, like in the example above.

So the question that remains is: Why cant we just omit the forward declaration at all when using the functions above? In the end, it would suffice for the compiler to know that all dict are pointers.

However, the compiler does perform type checks: It needs to verify that you don't do something like

...
int i = 12;
char* value = get_value(&i, "MyName");
...

It does not need to know how my_dict_t looks like, but it needs to know that &i is not the type of pointer get_value() expects.

like image 21
Michael Beer Avatar answered Oct 04 '22 17:10

Michael Beer