views:

894

answers:

7

I have a plain C code with *.c and *.h files in the workspace.
I have a header file 1.h declaring some structure as

struct my1
{ 
int a;
..
..
}my_t;

But when i try to declare a variable of type struct my1 in another header file 2.h as follows:-

struct my1 variable1;

It gives error at this declaration point.

Looks like my1 is undefined here in 2.h file.

In file 1.h I need to include 2.h, so in file 2.h I cannot include 1.h, for fear of recursive inclusion.

My question is:-

  1. What do i need to declare to resolve the compilation error in this case?

    This whole thing made me think about further questions about header file inclusions.

  2. How are the header files included, in what order, which header file first then which one?

  3. Will recursive inclusion of header files cause errors one file including other and other including first?

Could not post the actual code snippets for some security reason, so sorry if the question somewhat poses some readability problems.

A: 

It's been a while since I worked with C, but I think what you want to do is forward define my1.

In 2.h, try putting this near the top:

struct my1;

Sorry, I can't answer your other two questions.

Chris Shaffer
You only need to do that if you don't want to include the header file and you only reference the struct by a pointer (and don't access any of it's fields).
sharth
+4  A: 

You should start by putting an inclusion lock in all your .h files (this is called an include guard):

#ifndef ONE_H
#define ONE_H

//rest of header

#endif //ONE_H

That way you can include it multiple times.

Second:

typedef struct my1 { int a; .. .. }my_t;

You need a typedef in C (not in C++)

The headers are included in the order of inclusion.

If you compile a file abc.c which starts with:

#include "a.h"
#include "b.h"

then a.h will be included first, then b.h.

You could think of it, as if you paste the code in the file. It is included at that point.

Burkhard
@Burkhard: So if a.h internally includes some c.h, then that would get included first and Then b.h right?
goldenmean
And u mean #ifndef right?
goldenmean
You don't need to typedef. It just simplifies using the structure in a declaration because you can use the new name.
Eddie
But if there are multiple source files including various header files, then from which source file does the inclusion of header files begin?
goldenmean
@goldenmean: Yes and yes. Typo corrected.
Burkhard
You compile files (e.g. a.c and b.c) which includes a header (e.g. a.h and b.h). The inclusion is begins from a.c when compiling a.c and from b.c when compiling b.c. Clearer now?
Burkhard
A: 
// Header1.h
typedef struct tagHeader1
{
} Header1;

// Header2.h

struct Header1;

// Header2.c

#include "Header1.h"

Note: This only works for pointers (and in c++, references). If you have a reference to a complete object, the compiler will need to know about it.

Mark Ingram
+1  A: 

Header files are included in the order of include directives. Once the compiler sees an include directive it opens the file to include and simply inserts all of its contents into the including file.

If the included file has include directives inside, the same is done for them. This process continues until all of the include directives have been processed.

Only after that the compilation is started.

That's why if any file is included more than once (A included B and C; both B and C include D for example) you'll often see compiler complaining about redefinitons. To resolve this add inclusion locks (aka include guards) - the ifdef directives.

//file Header1
#ifndef Header1Guard
   #define Header1Guard
// all the header text here
#endif
sharptooth
But if there are multiple source files including various header files, then from which source file does the inclusion of header files begin?
goldenmean
This is usually up to the compiler. It may just get a list of files in the directory and follow that order, or use the order specified in a project or make file.
sharptooth
Anyway each source file is compiled separately and this order doesn't affect the inclusion process.
sharptooth
+1  A: 

I second the guard suggestion.

I religiously use the following header template:

#ifndef HELLOWORLD_H_
#define HELLOWORLD_H_

// Header stuff here.

#endif // HELLOWORLD_H_

When the compiler see's an #include, it simply replaces that line with the contents of the header file (minus any processed directives in the header). So, that means you can include the file in as many places as you like without risking recursive includes.

nbolton
+1  A: 

Every header file is included in every translation unit (source file) in which there is an include directive for it. This is intended, and will happen even with inclusion guards -- every translation unit that uses your struct needs to know how that struct is defined so that it can be laid out in memory the same way throughout all the translation units of your app. The inclusion guards just prevent it from being included multiple times within one translation unit. Include files will be included in the order you include them within that translation unit (and they'll be recursively included if include files include other files... as others have said). The order of translation units being compiled is up to you (or your IDE) to specify to the compiler. It shouldn't matter what that order is, however, since every translation unit is completely independent until it gets to the linking phase of the build process.

rmeador
+2  A: 

It's like the folks said before.

I just want to add that sometimes even #ifdef won't help you.

//file1.h
#ifndef F1
#define F1

#include "file2.h"

struct file1st {
  struct file2st *ptr;
};

#endif

//file2.h

#ifndef F2
#define F2

#include "file1.h"

struct file2st {
   struct file1st *ptr;
};

#endif

//main.c

#include "file1.h"
#include "file2.h"

/*
This will give you an error of **struct file1st not defined**
Let's see why: 

1) file1.h is included
2) file1.h includes file2.h before it declares anything
3) the definition of struct file2st occurs and it uses struct file1st which isn't declared yet
*/

int main(int argc, char* argv[]){
  struct file1st st1;
  struct file2st st2;

  return 0;
}

The way to work this out is:

//file1.h
    #ifndef F1
    #define F1

    struct file2st;//just declare, it will be defined later. 

    struct file1st {
      struct file2st *ptr; // ok, compiler KNOWS the size of struct file2st*(pointer)
      struct file2st file2Var;// NOT ok, compiler doesn't know sizeof(struct file2st)
    };

    #endif

    //file2.h

    #ifndef F2
    #define F2

    #include "file1.h"

    struct file2st {
       struct file1st *ptr;
    };

    #endif
Franco
You have #ifdef where #ifndef should be a couple of times there...
RBerteig