Home > OS >  How to overcome circular dependency while achive struct information hiding at the same time in C?
How to overcome circular dependency while achive struct information hiding at the same time in C?

Time:12-17

As you can see, I want to logically separate the table from the cursor implementation. In addition, I want to hide both the table and cursor information from the user. However, doing so will generate the following compiler error

./table.h:10:1: error: unknown type name 'Cursor'

The alternative solution is to forward declare struct or put the struct declaration into the header files. But they are NOT very elegant.

Or I just don't know how to use forward declaration in a "better" way.

Is there any other way to achieve what I am trying to do here?

Any help will be greatly appreciated.

cursor.h

#ifndef CURSOR_H
#define CURSOR_H

#include "table.h"

typedef struct Cursor_t Cursor; //struct data hiding

//struct Table; //alternative solution: forward declaration
//struct Table* cursor_get_table(Cursor* cursor);
Table* cursor_get_table(Cursor* cursor);
#endif

cursor.c

#include "cursor.h"

typedef struct Cursor_t {
    Table* table;
} Cursor;

//struct Table* cursor_get_table(Cursor* cursor) { //alternative solution
Table* cursor_get_table(Cursor* cursor) {
    return cursor->table; //warning: incompatible pointer types returning 'Table *'...
}

table.h

#ifndef TABLE_H
#define TABLE_H

#include "cursor.h"

typedef struct Table_t Table; //struct data hiding

//struct Cursor; //alternative solution: forward declaration
//struct Cursor* table_start(Table* table);
Cursor* table_start(Table* table); //error: unknown type name 'Cursor'
#endif

table.c

#include "table.h"

typedef struct Table_t {
} Table;

//struct Cursor* table_start(Table* table) { //alternative solution
Cursor* table_start(Table* table) {
    return 0;
}

main.c

#include <stdio.h>

#include "cursor.h"
#include "table.h"

int main() {
    Table* table;
    Cursor* cursor;
    printf("hello world\n");
    return 0;
}

Please note the main.c is just a test code. I am not trying to accomplish anything meaningful here.

CodePudding user response:

You have a circular dependency in your header files, so only one of them gets included in the other, depending on which file you're compiling.

Both header files need to see the forward declaration of the other's type, so create a third header with the types and include that in the existing headers.

types.h

#ifndef TYPES_H
#define TYPES_H

typedef struct Cursor_t Cursor;
typedef struct Table_t Table; 

#endif

cursor.h

#ifndef CURSOR_H
#define CURSOR_H

#include "types.h"

Table* cursor_get_table(Cursor* cursor);
#endif

table.h:

#ifndef TABLE_H
#define TABLE_H

#include "types.h"

Cursor* table_start(Table* table);
#endif

Your .c files would then have the struct definitions, but without the typedef since it already exsits.

CodePudding user response:

Forward struct declarations with pointer usage is also a form of data hiding. cursor.c could have no access to Table interna, and contain the Cursor definition.

This allows changes to the implementation without recompiling usages (by makefile).

You might need functions just between cursor.c and table.c, but that could even placed in a cursor_table.h or whatever style you like. Tightly coupled "classes" exist.

  • Related