Enrique Rodríguez Enrique Rodríguez - 2 months ago 6
C Question

How to use struct as argument of a function when the struct is declared in another file?

I'm writing a c project and I'm trying to keep all the struct declarations in the relevant .h files. This allows me to use them in any of the .c files by including the relevant header.
I'm also avoiding the inclusion of header files of my project in other header files. I guess this will make the code easier to read and maintain.

My question is how to avoid the inclusion of a header which contains the declaration of a struct in the header file that uses that struct. Is there any way of doing that?. (I didn't find an answer for this, sorry if it's duplicated).
Here is a snippet:

cmd.c

#include "cmd.h"
#include "params.h" //This allows usage of struct testPars

void move_parameters(struct testPars *testP) {
...
}


cmd.h

#ifndef CMD_H
#define CMD_H
#include "params.h" //I want to avoid this include in this file

void move_parameters(struct testPars *testP) ;
#endif


params.h

#ifndef PARAMS_H
#define PARAMS_H

struct testPars {
char name[16];
double value;
};
#endif

Answer

Overall, there's a lot of confusion about proper program design here.

I'm trying to keep all the struct declarations in the relevant .h files. This allows me to use them in any of the .c files by including the relevant header.

This is acceptable practice for quick & dirty programming where you have no private encapsulation, or if the structs are of a simple nature.

But for professional programs where the structs represent more complex ADTs etc, you should only keep a forward declaration in the header files, and define the struct inside the corresponding c file. This leads to private encapsulation and modularisation, i.e. good program design. (Search for examples of "opaque type" or "opaque pointers". The formal term for such forward declarations is incomplete type.)

What you are trying to do sounds like the above but completely backwards: expose the definition to the caller, but don't use it yourself. And obviously you can't use a struct that you haven't included and made visible to your program, because that doesn't make any sense.

I'm also avoiding the inclusion of header files of my project in other header files. I guess this will make the code easier to read and maintain.

This is a bad idea. Each of your header files is to be regarded as the public documentation of what the corresponding c file does and how it should be used. While the c file can be regarded as private data, the content is nothing that the caller should concern themselves with.

An important part of that header file documentation is to list all dependencies that this module has, so that other programmers can quickly take a glance at the top of your header file and immediately tell which files that are needed in order to compile this particular module.

Good program design strives for as few dependencies as possible: "loose coupling". Therefore all #includes are regarded as important information that should be put on top of the header file. Header files that aren't used should not be included.

The c file should not contain any includes except its own header file.