Suppose I have such a project structure:
main.c
#include "hashtable.h"
#include "list.h"
int main()
{
hash_table ht = calloc(1, sizeof(htable));
cmp_function f;
TLDI list;
return 0;
}
hashtable.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _HASH_TABLE_
#define _HASH_TABLE_
#include "list.h"
typedef int (*hash_function)(void*, int);
typedef struct _hasht_{
int maxElemNumber;
hash_function hf;
TLDI* key_array;
} htable, *hash_table;
void test2(cmp_function cmp);
#endif
list.h
#include "hashtable.h"
#ifndef _LINKED_LIST_
#define _LINKED_LIST_
typedef int (*cmp_function)(void*, void*);
typedef struct _node_ {
void *info;
struct _node_ *pre, *urm;
} TNode, *TLDI;
int test(hash_table ht);
#endif
and another two C files:
hash_func.c
#include "hashtable.h"
void test2(cmp_function cmp)
{
printf("test\n");
}
list_func.c
#include "list.h"
int test(hash_table ht)
{
return 1;
}
I want to use in hashtable.h
a typedef from list.h
, it's typedef struct...},*TLDI;
. In the same way, list.h
uses a typedef struct ...},*hash_table;
from hashtable.h
. Can I do something like this or I'm wrong? Cause I get this error while compiling whole project:
In file included from hashtable.h:7,
from main.c:1:
list.h:14:10: error: unknown type name ‘hash_table’
14 | int test(hash_table ht);
In file included from hashtable.h:7,
from hash_func.c:1:
list.h:14:10: error: unknown type name ‘hash_table’
14 | int test(hash_table ht);
I'm not strong in typedef
and headers, but if I would get an answer to this question or at least a source from where I could find out more about them I would be very grateful.
Two headers that rely to each other are not a show stopper if well-formed. What I observe is that your include guards don't enclose the full header but only part of it, this I think is wrong. The right way to use include guards is shown in this
example header some_component.h
:
#ifndef SOME_COMPONENT_H
#define SOME_COMPONENT_H
// include whatever you need here (*after* the opening guard):
#include "some_other_component.h"
// start type definitions and declarations *after* includes:
struct some_component_t {
// ...
};
#endif
This way, you headers will work most consistently:
I advise you to avoid placing definitions before includes, as this allows you to modify the content of the included content. What looks like a tempting idea at first, turns into a confusing nightmare in the long run in the vast majority of cases.
Another point is that if the definitions in the two headers really rely on each other, you should rethink your design.
Also, it's not clear why void test2(cmp_function cmp);
which relies on cmp_function
is declared in hashtable.h
and why int test(hash_table ht);
which relies on hash_table
is declared in list.h
; to me this seems like you were mixing up things here. In other words, by switching places of some declarations, you'd get rid of most of the entanglement.
You should also know that typedef
s and pointers are allowed on incomplete types, so it's possible to declare a pointer to a structure that is not yet defined. So, for example, the following compiles:
typedef int (*hash_function)(void*,int);
typedef int (*cmp_function)(void*,void*);
typedef struct _hasht_ hasht, *hash_table;
typedef struct _node_ TNode, *TLDI;
struct _node_ {
void *info;
struct _node_ *pre, *urm;
};
struct _hasht_{
int maxElemNumber;
hash_function hf;
TLDI* key_array;
};
... as does this (version without struct
typedef
s):
struct _node_ {
void *info;
struct _node_ *pre, *urm;
};
typedef int (*hash_function)(void*,int);
struct _hasht_{
int maxElemNumber;
hash_function hf;
struct _node_** key_array;
};