Home > Blockchain >  Avoid circular dependency in header files in C
Avoid circular dependency in header files in C

Time:02-04

I have two header files that refer to each other and that produce a compile error if I do not carefully put my includes on the right lines. Each of my header files matches with a srcs directory:

___include
|____matrixes.h
|____define.h
|____transformations.h
|____tuples.h
|____pixels.h
|____ppm.h
|____Myproject.h
|____error_handler.h
|____graphics.h

Basically, Myproject.h contains all #include I needed, while every other header files contain prototypes, typedefs, structs, #defines I needed for the respective srcs directory. But I guess I got something wrong. My problem comes from pixels.h, graphics.h and (maybe) Myproject.h. Here are they:

#ifndef PIXELS_H
# define PIXELS_H

# include "Myproject.h"

typedef uint32_t t_pixel;
typedef unsigned char t_color;

//////////////////////////
//# include "graphics.h"
//////////////////////////

// pixels/conversions.c
t_tuple pixel_to_point(t_image image, int i, int j);
t_tuple point_to_pixel(t_image image, double x, double y);

// pixels/print.c
void    print_pixel(t_pixel p, char *name);

// pixels/pixels.c
t_pixel pixel(t_color r, t_color g, t_color b, t_color a);
t_color get_a(t_pixel pixel);
t_color get_r(t_pixel pixel);
t_color get_g(t_pixel pixel);
t_color get_b(t_pixel pixel);

// pixels/ops.c
t_pixel add_pixel(t_pixel p, t_pixel q);
t_pixel sub_pixel(t_pixel p, t_pixel q);
t_pixel scal_pixel(float q, t_pixel p);
t_pixel mul_pixel(t_pixel p, t_pixel q);

#endif
#ifndef GRAPHICS_H
# define GRAPHICS_H

# include "Myproject.h"

typedef struct s_window{
    void    *mlx;
    void    *win;
} t_window;

typedef struct s_image {
    void    *mlx;
    void    *img;
    char    *addr;
    int     bits_per_pixel;
    int     line_length;
    int     endian;
    t_tuple origin;
    t_tuple extension;
}   t_image;

typedef struct s_canvas{
    t_window    window;
    t_image     image;
} t_canvas;

// graphics/graphics.c
t_window    *window(t_window *cvs);
t_image *image(t_image *img, void *mlx);
t_canvas    *canvas(t_canvas *canvas);
void    put_pixel(t_image img, int x, int y, t_pixel pixel);

// graphics/free.c
void    free_window(t_window *window);
void    free_image(t_image *image);
void    free_canvas(t_canvas *canvas);

#endif
#ifndef MYPROJECT_H
# define MYPROJECT_H

# include <unistd.h>
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <limits.h>
# include <stdbool.h>
# include <mlx.h>
# include <math.h>
# include <fcntl.h>
# include <sys/stat.h>
# include "libft.h"
# include "define.h"
# include "tuples.h"
# include "matrixes.h"
# include "pixels.h"
# include "graphics.h"
# include "ppm.h"
# include "error_handler.h"
# include "transformations.h"

#endif

As such, it did not compile with following error:

In file included from srcs/pixels/conversions.c:13:
In file included from include/miniRT.h:30:
include/pixels.h:22:24: error: unknown type name 't_image'
t_tuple pixel_to_point(t_image image, int i, int j);
                       ^
include/pixels.h:23:24: error: unknown type name 't_image'
t_tuple point_to_pixel(t_image image, double x, double y);

I understand the error because the pixel_to_point function takes a t_image as argument and in Myproject.h, graphics.h is included after pixels.h so it does not recognize the t_image type.
If I try to invert the graphics.h and pixels.h includes in Myproject.h, I just get the same error when a function from graphics.h needs the t_pixel type. I can make it run by uncommenting the commented #include graphics.h in pixels.h (because it is AFTER the t_pixel typedef) but I feel it is an ugly method.

Is there a rule to follow to avoid these issues ?

CodePudding user response:

Consider your project include files to form some sort of hierarchy.

Have pixel.h only include "tuples.h", etc. What is needed, not "Myproject.h".

Likewise for "graphics.h".


Other strategies exist.


IMO, typedef unsigned char t_color; should not exist in "pixels.h", but only in "color.h".

IOWs, I recommend that each object/function/constant/macro declared in a xyz.h begin with a xyz_ or the like. OP's current approach has names spaces all over the place defined in a given .h file. I see this as hard to follow and unnecessarily difficult to maintain.

I would also recommend to rename functions like add_pixel() to pixel_add() to lead with the key-prefix pixel.

  • Related