Circular Dependency Solution - C

I checked SO for duplicates of this, but couldn't find the exact solution for my problem.

I have a header file NvCommon.h

where I am using enum NV_DATA_TYPE

. This enum is defined in another title NvDefs.h

where I am using multiple structs and enums from NvCommon.h

. I am unable to build this due to circular dependency. I know forwrd enum declaration is not possible.

In this situation, what can be done? Is this a problem with my design? Do I have to enter a different header file to solve this problem?

I'm not a C expert. Please help me. My project might be in trouble and I know I can fix this circular dependency by introducing a different header file. What I would like to know is the only workaround . Look for alternative solutions if available.

I'll post the complete code in case it is helpful.

+3


source to share


5 answers


It can be helpful to define enums in their own files, and if you do, your problem goes away.



+10


source


If I understood your question correctly, you have something like this:

derpfoo.h:

#ifndef DERPFOO_H
#define DERPFOO_H

#include "derpbar.h"

typedef struct {
        char *nothing;
} FOO;

BAR foo (BAR derp) {
        return derp;
}

#endif

      

derpbar.h:

#ifndef DERPBAR_H
#define DERPBAR_H

#include "derpfoo.h"

typedef struct {
        char *nothing;
} BAR;

FOO bar (FOO derp) {
        return derp;
}

#endif

      

and then a simple derp.c:

#include "derpfoo.h"
#include "derpbar.h"

int main (void) {
        return 0;
}

      

One of my friends introduced this issue to me in some SDL code a while ago and it took me a while to figure out why he does what he does and how to fix it intelligently.

The purpose of splitting code like this is that derpfoo and derpbar are logically separate, but they are also, unfortunately, interdependent. The simplest solution I found is to combine them and separate them by anatomy, not logic:

derpstructs.h:

#ifndef DERPSTRUCTS_H
#define DERPSTRUCTS_H

typedef struct {
        char *nothing;
} FOO;

typedef struct {
        char *nothing;
} BAR;

#include "derpfunctions.h"

#endif

      

derpfunctions.h:

#ifndef DERPFUNCTIONS_H
#define DERPFUNCTIONS_H

#include "derpstructs.h"

BAR foo (BAR derp) {
        return derp;
}

FOO bar (FOO derp) {
        return derp;
}

#endif

      



and still a simple derp.c:

#include "derpstructs.h"
#include "derpfunctions.h"

int main (void) {
        return 0;
}

      

Note that derpstructs.h includes derpfunctions.h at the end, not at the beginning. This is not, strictly speaking, necessary, but if you intend to include them within each other, you must include function definitions after defining the structures on which they depend in all possible inclusion paths. Moving on ...

This solution works, but it doesn't exactly match the original philosophy, which started the problem with the fact that the two parts are logically separate and should be kept in code.

The answer to both is to separate everything further and further customize the inclusion paths.

derpfoostructs.h includes derpbarstructs.h first and then defines a FOO structure and then optionally includes derpfoofunctions.h and derpbarfunctions.h at the end.

derpbarstructs.h includes derpfoostructs.h first and then defines a struct BAR and then optionally includes derpfoofunctions.h and derpbarfunctions.h at the end.

derpfoofunctions.h includes derpfoostructs.h and derpbarstructs.h first, then includes derpbarfunctions.h, and then defines its functions.

derpbarfunctions.h includes derpfoostructs.h and derpbarstructs.h first, then includes derpfoofunctions.h, and then defines its functions.

derp.c includes derpfoostructs.h and derpbarstructs.h and then includes derpfoofunctions.h and derpbarfunctions.h and then continues to do whatever it needs to do.

This satisfies both of the desired requirements. It removes circular dependencies and still maintains a logical separation of two logically separate blocks of code. You get two files to edit when moving from project to project instead of one, but it at least keeps the modified code separate from the immutable one. This, and this is the only solution I have found.

Hope this helped. Good luck with your projects.

+5


source


Cyclic dependencies can mean that you are overriding your interface. Merge both files into Nv.h. If this trivially solves the problem, it means that you have designed the interface incorrectly.

+2


source


check it

How to correctly declare and define variables, libraries, functions, etc. It can make a difference.

+1


source


I tried to simulate this issue based on your description. In my implementation, I tested three things: 1) declaring but not defining NV_DATA_TYPE in NvDefs.h, (2) declaring and defining NV_DATA_TYPE in NvDefs.h, and (3) defining NV_DATA_TYPE in NvDefs.h, but declaring NvCommon.h. Moreover, as your description, I created some structures in NvCommon.h and accessed these objects in NvDefs.h. In each case - with and without guards in the header files - the code is compiled and executed with the correct results.

Is it possible that your circular dependency is somewhere else in your header files besides the NV_DATA_TYPE enumeration?

+1


source







All Articles