Header include order... Going crazy

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am creating a generic "library" (really just a .h/.c file pair) for interfacing to a particular chip. The library will be used in multiple applications. Each application will have several specific functions (hard coding some messages to the device, etc.). I plan on placing these in a separate file.

I have a struct defined in the library header that gets used everwhere to hold data for packets to be sent to the device.

When I try to include the application specific files, it appears to matter WHERE I include them from.

Scenario 1 (all headers guarded by #ifndef...):

fooLib.h:

   #include "fooLibDef.h"  //bunch of constants
   #include "fooAS.h"      //Application Specific file

     typedef struct fooPacket {
        uint8_t packetClass;
        uint8_t packetID;
        uint16_t length;
        uint8_t *payload;
        uint8_t crcGood;
     } fooPacket_t;

fooLib.c:

#include "fooLib.h"

fooAS.h:

#include "fooLib.h"
#include "fooLibDef.h"

void foo2(fooPacket_t *packet, uint8_t lenAvail);

In this scenario, I get an error, pointing to the declaration of foo2 -- fooPacket_t is not recognized.

In Scenario 2, I remove the #include "fooAS.h" from fooLib.h, and instead, include it in fooLib.c:

fooLib.c:

#include "fooLib.h"
#include "fooAS.h"

This compiles with no warnings. Why is that?

Science is not consensus. Science is numbers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
fooLib.h:

...
#include "fooAS.h"      //Application Specific file
...

fooAS.h:

#include "fooLib.h"
...

This create a circular reference (a bad thing). Think about what the compiler does with #include: it replaces the #include xxx with the contents of the file xxx.

Also, even if you remove the #include "fooLib.h" from fooAS.h, you still have a problem since now foo2 is defined before fooPacket.

I would just put:

void foo2(fooPacket_t *packet, uint8_t lenAvail);

into fooLib.h (after the definition of fooPacket) and drop fooAS.h all together.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The idea is to have a set of generic files used in multiple projects (unchanged), and then a set of application specific files that get modified for each project.

If I move all the stuff the fooAS.h file needs to the fooLibDef.h file (namely, the struct definition), then I think I remove the circular includes (fooLibDef.h does not include anything), and get the portability I am looking for in the generic files.

Edit: except that didn't work...

Science is not consensus. Science is numbers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Did you put the declaration of foo2 after the definition of fooPacket?

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What I am now trying (unsuccessfully):

fooPacket is defined in fooDef.h

fooAS.h includes fooDef.h

foo2 is declared in fooAS.h, after the include statement.

This does not work.

Edit: I have been staring at this too long. I had removed the wrong #include statement (i.e., fooLibDef.h rather than fooLib.h). It is now compiling and working correctly (tested in hardware).

Per your suggestion, I now have no circular paths through include statements.

Thank you

Science is not consensus. Science is numbers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A way to avoid having circular references occurring, it is wise to put "guards" around your header files like this:

//foo.h
#ifndef __FOO_H__
#define __FOO_H__

//...body of the .h file

#endif

This way if you accidentally include a file twice within the same .c file, no harm will come of it.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Good point. But from my first post:

hobbss wrote:

Scenario 1 (all headers guarded by #ifndef...):

Science is not consensus. Science is numbers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As a rule, a good way to debug this kind of thing is to use -save-temps and look at the .i file.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just out of interest why would the lib .h or .c have any knowledge of application specific headers or functions?

If foolib.c is calling foo2() then I'd ask what the library was doing calling an application specific function? If the library really does need to call-back to application functions then do it "properly": register call-backs then call them back. The call-back interface can (obviously?) only use things known to the lib, not things invented in the application (typedef's, enum's, struct's and so on).