C header file The chicken or The egg problem - c

I was developing a c program (a compositor) and I suddenly ran into a problem.
Here is the problem:
I have two header files server.h and seat.h which consists of one struct each.
server.h
typedef struct
{
const char *socket;
struct wl_display *wl_display;
struct wl_event_loop *wl_event_loop;
struct wlr_backend *backend;
struct wlr_renderer *renderer;
struct wlr_compositor *compositor;
struct wlr_output_layout *output_layout;
Seat *seat; // the seat struct from seat.h
struct wl_list outputs;
struct wl_listener output_listener;
} Server;
bool init_server(Server *server);
void run_server(Server *server);
void destroy_server(Server *server);
seat.h
typedef struct
{
Server *server; // the server struct from server.h
struct wlr_seat *wlr_seat;
struct wl_listener input_listener;
struct wl_listener destroy_seat;
} Seat;
Seat *create_seat(Server *server);
void handle_new_input(struct wl_listener *listener, void *data);
void destroy_seat(struct wl_listener *listener, void *data);
The main problem is that it creates a loop of header files so when I compile it causes error.
I have read about the problem in here C header file loops. And I tried this it worked in the case of struct but when I call the create_seat() function it is telling that the type is mismatched. In my case I'm using typedef too so it's a little bit confusing.
Since the actual code is not good to run on any machines (because it need dependencies and so on) please use this code as the reference, this explains my actual problem.
I uses meson build system. If I compile the program using ninja it ends in an infinite loop.
Here's the code:
main.c
#include <stdio.h>
#include "server.h"
#include "seat.h"
int main()
{
Server server;
server.id=10;
Seat seat;
seat.id=20;
server.seat=seat;
seat.server=server;
printSeatId(server);
printServerId(seat);
return 0;
}
server.h
#include "seat.h"
typedef struct
{
Seat seat;
int id;
} Server;
void printSeatId(Server s);
seat.h
#include "server.h"
typedef struct
{
Server server;
int id;
} Seat;
void printServerId(Seat s);
server.c
#include <stdio.h>
#include "server.h"
void printSeatId(Server s)
{
printf("%d",s.seat.id);
}
seat.c
#include <stdio.h>
#include "seat.h"
void printServerId(Seat s)
{
printf("%d",s.server.id);
}
meson.build - in src folder
sources = files(
'main.c',
'server.c',
'seat.c'
)
executable(
'sample',
sources,
include_directories: [inc],
install: false,
)
meson.build in project folder
project(
'sample',
'c',
version: '1.0.0',
meson_version: '>=0.56.0',
default_options: ['c_std=c11','warning_level=2'],
)
add_project_arguments(
[
'-DWLR_USE_UNSTABLE',
'-Wno-unused',
'-Wno-unused-parameter',
'-Wno-missing-braces',
'-Wundef',
'-Wvla',
'-Werror',
'-DPACKAGE_VERSION="' + meson.project_version() + '"',
],
language: 'c',
)
cc = meson.get_compiler('c')
inc = include_directories('include')
subdir('src')
Here is the directory structure :
<project_folder>
|--->src
| |--->server.c
| |--->seat.c
| |--->meson.build
|
|--->include
| |--->server.h
| |--->seat.h
|
|--->meson.build
I have given the same directory structure of the original project.

The way to resolve the conflict is by adding a forward declaration of an incomplete structure type. The struct type used in the forward declaration needs a tag and the same tag is used for the complete declaration of the same type. For symmetry, it makes sense to add forward declarations of both the Seat and Server structure types. The typedef type definitions can be moved to one or more new header files that are included by the seat.h and server.h header files. The header files need to define guard macros to avoid multiple definition conflicts.
For example:
seat_server_t.h
#ifndef SEAT_SERVER_T_H__INCLUDED
#define SEAT_SERVER_T_H__INCLUDED
typedef struct Seat_s Seat;
typedef struct Server_s Server;
#endif
seat.h
#ifndef SEAT_H__INCLUDED
#define SEAT_H__INCLUDED
#include "seat_server_t.h"
/* Other includes for struct wl_listener, etc. here... */
struct Seat_s
{
Server *server;
struct wlr_seat *wlr_seat;
struct wl_listener input_listener;
struct wl_listener destroy_seat;
};
Seat *create_seat(Server *server);
void handle_new_input(struct wl_listener *listener, void *data);
void destroy_seat(struct wl_listener *listener, void *data);
#endif
server.h
#ifndef SERVER_H__INCLUDED
#define SERVER_H__INCLUDED
#include "seat_server_t.h"
/* Other #include's for struct wl_display, etc. here... */
struct Server_s
{
const char *socket;
struct wl_display *wl_display;
struct wl_event_loop *wl_event_loop;
struct wlr_backend *backend;
struct wlr_renderer *renderer;
struct wlr_compositor *compositor;
struct wlr_output_layout *output_layout;
Seat *seat; // the seat struct from seat.h
struct wl_list outputs;
struct wl_listener output_listener;
};
bool init_server(Server *server);
void run_server(Server *server);
void destroy_server(Server *server);
#endif
The new header file seat_server_t.h does not need to be included directly by the .c files such as main.c. It can be treated as for internal only by the other header files, seat.h and server.h. It could also be split into two separate header files (one for each typedef) if desired.

If you just need a pointer to the other struct, you can forward-declare that one, like this:
typedef struct Server Server;
typedef struct
{
Server *server; // the server struct from server.h
struct wlr_seat *wlr_seat;
struct wl_listener input_listener;
struct wl_listener destroy_seat;
} Seat;

Related

Typedef not recognized when in header file in C

So I defined a struct in module.c and typedef'd it in module.h, as someone in this thread told to do (How do I refer to a typedef in a header file?). But when I try to compile the project I get lots of errors, such as:
error: variable 'messi' has initializer but incomplete type
error: unknown field 'id' specified in initializer
error: storage size of 'messi' isn't known
But if I put all my code in the same file, it compiles and runs just fine. I'm kinda new to C and this is making me crazy because I can't find a solution anywhere. Searching the errors by themselves I find people having problems from typos and from using the struct after they typedef'd, which doesn't seem to be the case for me.
My code is something like this:
module.c
#include "module.h"
struct s_player{
int id;
char name[256];
struct s_player *next;
};
module.h
typedef struct s_player player;
main.c
#include "module.h"
player messi = {.id = 158023, .name = "Lionel Andres Messi Cuccittini", .next = NULL};
Move the declarations (struct, typedef) to your header file module.h:
struct s_player{
int id;
char name[256];
struct s_player *next;
};
typedef struct s_player player;
then in your main.c file:
#include <stdio.h>
#include "module.h"
int main() {
player messi = {.id = 158023, .name = "Lionel Andres Messi Cuccittini", .next = NULL};
printf("%s", messi.name);
}

Unknown type name in C header file

I'm facing an issue when I compile my project. I'm trying to put in a queue a struct which I've decalred in a header file like this:
Appointment functions header file ("signupFunctions.h" is where I've my "Patient" declaration):
#ifndef appointmentFunctions_H__
#define appointmentFunctions_H__
#include "queueFunctions.h"
#include "signupFunctions.h"
typedef struct{
int cough;
int rDistress;
int fatigue;
int fever;
}symptoms;
typedef symptoms *Symptoms;
typedef struct {
Patient patient;
Symptoms symptoms;
int day;
int mon;
int year;
int flag;
}appointment;
typedef appointment *Appointment;
int getSymptomsValue(Appointment A);
void setSymptoms(Appointment A);
void requestAppointment(Patient P, qNodePtr *head, qNodePtr *tail);
#endif
Queue functions header file:
#ifndef queueFunctions_H__
#define queueFunctions_H__
#include "appointmentFunctions.h"
typedef struct qNode{
Appointment A;
struct qNode *next;
}QueueNode;
typedef QueueNode *qNodePtr;
void printQueue(qNodePtr currentPtr);
int isEmpty(qNodePtr head);
void dequeue(qNodePtr *head, qNodePtr *tail);
void enqueue(qNodePtr *head, qNodePtr *tail, Appointment App);
#endif
Once I compile I get:
In file included from appointmentFunctions.h:4:0,
from menuFunctions.h:5,
from main.c:4:
queueFunctions.h:7:2: error: unknown type name 'Appointment'
Appointment A;
^~~~~~~~~~~
queueFunctions.h:16:46: error: unknown type name 'Appointment'
void enqueue(qNodePtr *head, qNodePtr *tail, Appointment App);
^~~~~~~~~~~
In file included from appointmentFunctions.h:4:0,
from menuFunctions.h:5,
from signupFunctions.c:5:
queueFunctions.h:7:2: error: unknown type name 'Appointment'
Appointment A;
^~~~~~~~~~~
queueFunctions.h:16:46: error: unknown type name 'Appointment'
void enqueue(qNodePtr *head, qNodePtr *tail, Appointment App);
^~~~~~~~~~~
..and so on. What's the problem? Thanks in advance.
In appointmentFunctions.h you include queueFunctions.h
So when queueFunctions.h is read the type Appointment is unknown.
It doesn't help you that queueFunctions.h also includes appointmentFunctions.h because at that time appointmentFunctions_H__ is already defined, i.e. the file content will not be read.
If file X.h depends on something from file Y.h and at the same time Y.h depends on something from file X.h you have a design error that must be fixed.
As far as I can see the dependency is only pointer to struct so you can get rid of the dependency by forward declaring the struct.
In queueFunctions.h do these changes:
#include "appointmentFunctions.h" --> struct appointment;
Appointment --> struct appointment*
BTW: It's opinion based but most programmers avoid typedef's for pointers. If it's done it's typically a good idea to use a name that clearly tells that this is a pointer, i.e. something like:
typedef appointment *Appointment; --> typedef appointment *appointmentPtr;
You recursively included one header in another
#ifndef appointmentFunctions_H__
#define appointmentFunctions_H__
#include "queueFunctions.h"
#include "signupFunctions.h"
//...
and
#ifndef queueFunctions_H__
#define queueFunctions_H__
#include "appointmentFunctions.h"
//...
So the compiler issues an error.
You shall not do that.
That is the header appointmentFunctions.h at once includes the header queueFunctions.h in which there is declaration
typedef struct qNode{
Appointment A;
struct qNode *next;
}QueueNode;
but the declaration of Appointment is not visible yet. It follows after the inclusion of the header queueFunctions.h.

Use typedef from one header in another and vice versa

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:
either read completely
or completely ignored
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 typedefs 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 typedefs):
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;
};
The overall interdependency of the headers is kind of ugly, but the errors can be corrected with some forward declarations:
hashtable.h
#ifndef _HASH_TABLE_
#define _HASH_TABLE_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _hasht_ htable, *hash_table;
typedef int (*hash_function)(void*,int);
#include "list.h"
struct _hasht_ {
int maxElemNumber;
hash_function hf;
TLDI* key_array;
};
void test2(cmp_function cmp);
#endif
list.h
#ifndef _LINKED_LIST_
#define _LINKED_LIST_
typedef struct _node_ TNode, *TLDI;
typedef int (*cmp_function)(void*,void*);
#include "hashtable.h"
struct _node_ {
void *info;
struct _node_ *pre, *urm;
};
int test(hash_table ht);
#endif

C - Unknown type name

I need to build a "social network" for college, but I always get unknown type name 'List' while compiling. I removed a lot of functions from my headers, but I still get the same error and I don't know why.
I've got 3 headers:
My friend's header
#ifndef FRIEND_H
#define FRIEND_H
#include "ListHeadTail.h"
typedef struct Friend{
int id;
struct Friend *nextFriend;
}Friend;
void printFriends(List *l);
void removeFriend(List *l);
void addFriend(List *l);
#endif /* FRIEND_H */
My list header:
#ifndef LISTHEADTAIL_H
#define LISTHEADTAIL_H
#include "Student.h"
typedef struct pStudent{
struct pStudent *ant;
Student *s;
struct pStudent *prox;
}pStudent;
typedef struct list{
pStudent *head;
pStudent *tail;
}List;
void startList(List *l);
void printList(List *l);
void freeList(List *l);
#endif /* LISTHEADTAIL_H */
My student's header
#ifndef STUDENT_H
#define STUDENT_H
#define MAX 51
#include "Friend.h"
#include "ListHeadTail.h"
typedef struct Student{
int id;
char name[MAX];
Friend *friends;
}Student;
Student* readStudent ();
void printStudent(Student* a);
void changeData(List *l);
#endif /* STUDENT_H */
My main:
#include <stdio.h>
#include <stdlib.h>
#include "ListHeadTail.h"
#include "Friend.h"
#include "Student.h"
int main(int argc, char** argv) {
List l;
startList(&l);
freeList(&l);
return (EXIT_SUCCESS);
}
Thanks for reading.
Here's the (first) error I get when I try to compile this set of files:
$ cc main.c
In file included from main.c:4:
In file included from ./ListHeadTail.h:4:
In file included from ./Student.h:6:
./Friend.h:11:19: error: unknown type name 'List'
void printFriends(List *l);
Look at the file names and line numbers. Note that at ListHeadTail.h line 4, you've already defined LISTHEADTAIL_H, but you haven't yet reached the actual declaration of List. You then go into Student.h, and from there into Friend.h. That includes ListHeadTail.h again -- but since LISTHEADTAIL_H is already defined, this include does nothing. So you continue through Friend.h with no declaration of List, and therefore get an error on the declarations that reference it.
As noted by #lurker in their comment, the basic issue here is circular dependency, and a simple fix is forward declaration. In this case, you could simply modify Friend.H, replacing #include "ListHeadTail.h" with typedef struct list List;.
But to me this is a bit hacky. If you shift the order of includes somewhere, the build might break again.
I think the real problem is that the declarations of the functions (printFriends, etc.) don't belong in Friend.h; they belong in ListHeadTail.h. The functions have nothing to do with the Friend type. Sure, they have "Friend" in their names, but the only type referenced in the declarations is List. So they belong in ListHeadTail.h. Same goes for the changeData function in Student.h.
In an object-oriented design (say, in Java), these functions would all probably be methods of the List class, and would be declared in that class's source file.

Defining a struct error in VS 2015

I have a struct declaration in my header
#ifndef _MAP_IMPL_
typedef struct { } *MapADT;
#endif
And I then define it in my source file like this
typedef struct Key {
void * value;
void * keyVal;
struct Key * next;
} Key;
// Defining struct MapADT
typedef struct {
Key *keys; // Head of keys
bool (*equals)( const void *a, const void *b );
}*MapADT;
#define _MAP_IMPL_
#include "mapADT.h" // Header file
This works perfectly fine on Linux, but for some reason VS really hates it.
Is there any work around to this?
Visual Studio gives me an error indicating that
"C requires that a struct or union has at least one member"

Resources