-2

I have the following files:

A.h

#ifndef __A_H_
#define __A_H_

#include <B.h> // contains foo_t
typedef struct {
     foo_t foo;
     ...
} baz_t;

#endif

B.h

#ifndef __B_H_
#define __B_H_

#include <A.h> // contains baz_t
typedef struct {
     ...
} foo_t;

extern int useful_func(baz_t d);

#endif

When I compile this B.h refuses to compile complaining error: unknown type name 'baz_t'

I am assuming this error is owing to circular dependency between the two files. But I am wondering how do I forward declare baz_t to solve this? I found answers relating to circular dependencies between structs. But I am unsure how I would solve this. I would appreciate some help here. I am looking for a strictly C99 solution.

EDIT

  1. I previously forgot to mention this but I have already used include guards.
  2. A very obvious solution as suggested by user KamilCuk is moving useful_func to A.h. This has also occured to me but software organization wise useful_func unfortunately belongs to B.h. This problem could be a reflection of a poor design as well.
Abhiroop Sarkar
  • 2,251
  • 1
  • 26
  • 45
  • 1
    Move `extern int useful_func(baz_t d);` to `A.h` and remove `#include ` from `B.h` - problem solved. – KamilCuk Nov 04 '20 at 22:40
  • 1) I hope you're using [#include guards](https://en.wikipedia.org/wiki/Include_guard). 2) You don't need the "extern" qualifier; the prototype `int useful_func(baz_t d);` should suffice. 3) [System headers](https://www.tutorialspoint.com/cprogramming/c_header_files.htm) use the `#include` syntax. You probably want double-quotes - `#include "xyz.h"`. – paulsm4 Nov 04 '20 at 22:45
  • Hi @KamilCuk you are absolutely right, but I added an EDIT section now mentioning why I did not take that approach. – Abhiroop Sarkar Nov 04 '20 at 23:02
  • Make a new header, `"useful_func.h"` that contains the extern for `useful_func` (and includes the necessary headers). This would then also allow for "B.h" to not include "A.h" anymore. – 1201ProgramAlarm Nov 04 '20 at 23:11

2 Answers2

-1

You can use forward declaration as follows:

struct foo;

typedef struct {
    struct foo foo;
    ...
} baz_t;

And then use it normally on B.h

That said, circular dependencies can be avoided is you define everything on a third header that you use as interface. It would be cleaner, but it's not always possible.

Juan
  • 54
  • 4
  • 2
    This would work if the `struct` contained a pointer to `foo`. But the forward declaration isn't enough to use a `foo` itself as a member or parameter type, or anything else which needs the size and contents of a `foo`. – rici Nov 04 '20 at 23:08
-1

Typically, one would pass pointers to structures rather than passing them by value. If that would be acceptable, things are easy, since C compilers will accept a declaration:

void doSomethingWithAFoo(struct foo *it);

without regard for whether they have seen any definition for struct foo. Indeed, compilers will even accept function definitions like:

void doSomethingWithAFooTwice(struct foo *it)
{
  doSomethingWithAFoo(it);
  doSomethingWithAFoo(it);
}

without having to know or care about whether, where, or how struct foo is defined.

Note that an advantage of using struct tag syntax rather than typedef names is that prototypes using the struct tag syntax don't require declaring or defining anything that can't be harmlessly redeclared arbitrarily many times.

supercat
  • 77,689
  • 9
  • 166
  • 211