How to match .c and .h properly? - c

I have a C project and I really don't get how to manage .c and .h.
I've been using a method for years but now I have to create codes without any warnings, so I need to change the way I do it.
Here is how I'm doing it:
Each .c have a .h with the same name. Even main.c has a main.h.
In each .c, I include the matching .h, so I have only one include per .c.
In main.h, I include all the libraries I need, like stdio stdlib and so on. I also declare my enumerations and structures there.
Finally, in every other .h, I include the main.h which contains the structures, enums and libraries.
I understand that by doing that, I call main.h a lot of time, but I use the #ifndef and #define in every .h.
Also, I each .h contains the prototypes of the functions in their corresponding .c
How should I manage .c and .h?
I forgot to mention that the problem is that I get a warning for every single function: "implicit declaration of function"
Here is an example with four files :
main.c :
#include "main.h"
int main()
{
// code
}
int save(Player players[2], int currentPlayer)
{
// code
}
int load(Player players[2], int* currentPlayer)
{
// code
}
main.h :
#ifndef MAIN_H
#define MAIN_H
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#include <string.h>
#include <math.h>
typedef enum Direction Direction;
typedef enum Orientation Orientation;
typedef enum ShipType ShipType;
typedef enum CaseType CaseType;
typedef enum Status Status;
typedef enum PlayerType PlayerType;
enum Direction
{
Nord=0, Est=1, Sud=2, Ouest=3
};
enum Orientation
{
None=0, Horizontal=1, Vertical=2
};
enum ShipType
{
SousMarin=1, Destroyer=2, Croiseur=3, Cuirasse=4
};
enum CaseType
{
Undiscovered=0, Empty=1, Hit=2, Detected=3, Discovered=5
};
enum Status
{
Undamaged=0, Damaged=1, Drowned=2
};
enum PlayerType
{
Human=0, Computer=1
};
typedef struct Map Map;
typedef struct Ship Ship;
typedef struct Player Player;
struct Map
{
int width, height;
int* cases;
};
struct Ship
{
int x, y, length, firstShoot, color;
int hasBeenDiscovered;
Orientation orientation;
ShipType type;
Status status;
};
struct Player
{
int totalShips;
int activeShips;
Map map[2];
char lastMoves[5][128];
Ship* ships;
PlayerType type;
int shipcolor[4];
int shipNumber[4];
int color;
};
int save(Player players[2], int currentPlayer);
int load(Player players[2], int* currentPlayer);
#endif // MAIN_H
IA.c :
#include "IA.h"
int IA(Player* IA, Player* enemy)
{
// code
}
// And all my other functions
IA.h :
#ifndef IA_H
#define IA_H
#include "main.h"
int IA(Player* IA, Player* enemy);
void endIATurn(Player* IA);
int enemyShipDiscovered(Map map, int* x, int* y, int SousMarinSpecific);
Ship* bestFriendlyActiveShip(Ship* ships, int totalShips, int SousMarinSpecific);
int friendlyShipDiscovered(Ship** ship, Ship* ships, Map map, int totalShips, int SousMarinSpecific);
int hitShipButNotDrowned(Player* IA, Player enemy, int totalShips, int* x, int* y);
int hasAtLeastOneMoveableShip(Player player);
int hasUndiscoveredCases(Player player);
void getUndiscoveredCoordoonnees(Map map, int* x, int* y);
int findNextCaseToShootAt(Map map, Ship ship, int* a, int* b);
#endif // IA_H
All my other .h are like IA.h

For foo.h and foo.c:
Use foo.h to tell other source files about things that foo.c provides. So foo.h will declare functions that are (a) defined in foo.c and (b) called from other source files. It will also declare any types or other things that those functions need or that other source files need in able to be able to use the functions.
In foo.h, only use #include to include header files that foo.h itself needs.
In foo.c, use #include "foo.h". This has two purposes: (1) It declares things that foo.c may need, without having to duplicate those declarations in foo.c. (2) It ensures that foo.c is using the same declarations that other source files see when they include foo.h, so any conflicts between declarations in foo.h and definitions in foo.c will produce compiler warnings or error messages.
If foo.c needs any headers that foo.h, include them in foo.c, not foo.h. Similarly, if foo.c has any functions that it uses for itself but does not expect other source files to use, declare them only in foo.c. Keep things that are just for foo.c inside foo.c. Use foo.h only for exporting things to other source files.
If there are any types or other declarations used by your program generally:
Put them in a suitably named file (e.g., bar.h for types involving some bar concept) and include it. Largely, you can treat bar.h as a pair bar.h and bar.c described above except that bar.cis empty.
Generally, there is no reason to make a main.h. Usually, main.c uses things that other source files provide and does not provide things for other sources to use (except that main is called by the C run-time start-up code).

I suggest the following:
Divide your functions in different .c files as you already do. For every .c create a .h
In every .h insert its include guard:
Within the include guard, start by including the .h of the libraries you need to declare your functions or to define structs, e.g. #include <stdlib.h> if you use size_t parameters.
Within the include guard, insert the structs, enums, ... you need exported
Within the include guard, insert the function declarations.
In every .c start by including its corresponding .h, then include other libraries needed to implement your functions, then put in the definitions.
Don't make a main.h or common.h, unless you have extremely good reasons for it (I know this will be commented against, but everyone has its style).
In main.c include what you need. You'll be including much less than you think.

Related

Why does my compiler not recognise a typedef in another included header file?

I have a problem where the compiler (linker?) does not seem to detect a typedef in another included header file. I have two header files:
// ConstantsVariables.h
#ifndef CONSTANTSVARIABLES_H
#define CONSTANTSVARIABLES_H
#include "CellList.h"
extern double boxLength_x, boxLength_y;
typedef struct Position {
double x;
double y;
} Position;
typedef struct Particle {
Position position;
int inWhichCell;
double localOrientation;
double initialAngle;
double rotatedAngle;
int insideGrain;
} Particle;
#endif /* CONSTANTSVARIABLES_H */
and
// CellList.h
#ifndef CELLLIST_H
#define CELLLIST_H
#include "ConstantsVariables.h"
typedef struct Cell {
int numParticles;
Particle **particles;
} Cell;
typedef struct CellList {
int numCols, numRows, numCells;
double cellLength_x, cellLength_y;
Cell *cells;
} CellList;
CellList *createCellList(void);
void destroyCellList(CellList *cellList);
#endif /* CELLLIST_H */
with matching .c files that implement the CellList functions and definitions for boxLength_x/y. However, when I try to compile my main file, which has these headers included and uses the variables/functions in them, I get an error in CellList.h saying unknown type name 'Particle'. What am I missing?
ConstantsVariables.h includes CellList.h before it has typedef … Particle;. CellList.h uses Particle, so Particle is not defined where CellList.h uses it.
Although CellList.h has #include "ConstantsVariables.h", at that point ConstantsVariables.h has already defined CONSTANTSVARIABLES_H, so the #ifndef CONSTANTSVARIABLES_H in ConstantsVariables.h causes the rest of the contents of ConstantsVariables.h not to be processed.
You should design your source and header files to form a tree structure: Each file should include only files “lower” in the tree. (In computer science, tree structures are generally drawn with the root node at the top and leaves toward the bottom.) There should be no loops in the includes.
Nothing in ConstantsVariables.h depends on anything in CellList.h, so there is no need for ConstantsVariables.h to #include "CellList.h" at its beginning. It could be removed.
If you intended ConstantsVariables.h to be some general header file for your project that can be included so that every source file can include it and not pick out individual headers to include, then it should be the file that depends on other headers and other headers should not depend on it. That means CellList.h should not have #include "ConstantsVariables.h". Instead, move the declarations in ConstantsVariables.h to another file, such as one named PositionParticle.h. Inside ConstantsVariables.h, replace the moved declarations with #include PositionParticle.h. In CellList.h, change #include "ConstantsVariables.h" to #include "PositionParticles.h".

how to use a struct defined in a certain header file from another header in C?

I have two headers files, stack.h
#ifndef __STACK_H__
#define __STACK_H__
typedef struct StackElement_
{
int value;
struct StackElement_ *next;
} StackElement, *Stack;
/*----------------------Prototypes----------------------*/
Stack new_stack();
void push_to_stack(Stack *, int);
int pop_stack(Stack *);
int peek_stack(Stack);
int stack_length(Stack);
void print_stack(Stack);
Bool is_empty_stack(Stack);
void clear_stack(Stack);
/*------------------------------------------------------*/
#endif
and utils.h
#ifndef __UTILS_H__
#define __UTILS_H__
#define INT_MIN -2147483648
/*------------------------Typedef-----------------------*/
typedef enum Boolean_ {
FALSE,
TRUE
} Bool;
/*------------------------------------------------------*/
#endif
In stack.h, I need to know Bool but when I include utils.h in stack.c, the structure is still not known in stack.h. How to do this without having to define it directly in stack.h?
You need to include utils.h in stack .h (not stack.c). The #include statements are part of the C macro language, which is a simple pre-processor. It literally takes the file given as the filename (#include filename) and inserts it into your program (during the pre-processor stage of the compile).
A source file or include file should include all files necessary.
So if stack.h is dependent on declarations in util.h, then you should #include "util.h" in stack.h. That way, any module that includes stack.h doesn't need to worry about also including util.h and putting it in the right order.
If a module decides to include both that should be fine as well. The include guards you've added should address that.
You didn't show the source of stack.c, but you most likely included stack.h before util.h. That would explain your issue since the definitions needed by stack.h appear after them instead of before.

need a workaround for a "multiple definition" error

A toy code illustrating my problem is as follows:
stuff.h:
#ifndef STUFF
#define STUFF
int a;
int testarr[]={1,2,3};
#endif
fcn.h:
#include "stuff.h"
int b[]={5,6,7};
void fcn();
main.h:
#include "stuff.h"
#include <stdio.h>
fcn.c:
#include "main.h"
void fcn() {
printf("Hello\n");
}
main.c:
#include "main.h"
#include "fcn.h"
int main() {
fcn();
printf("HI\n");
}
An attempt to compile fails with:
/g/pe_19976/fcn_2.o:(.data+0x40): multiple definition of `testarr'
/g/pe_19976/main_1.o:(.data+0x40): first defined here
After doing some reading, I realize that defining the array testarr in the header file is a problem. But the thing is, in my real code, several files need access to testarr and it needs to have the same assigned values everywhere. I guess I could put it in main.h (?) but even if that would work, in my real code it logically belongs in stuff.h. How do I solve this conundrum?
BTW, based on something else I found, I tried defining testarr as extern but got the same problem.
When you put a variable definition into a header file, any .c file that includes it will have a copy of that variable. When you then attempt to link them, you get a multiple definition error.
Your header files should contain only a declaration of the variable. This is done using the extern keyword, and with no initializer.
Then in exactly one .c file, you put the definition along with an optional initializer.
For example:
main.c:
#include "main.h"
#include "fcn.h"
int a;
int testarr[]={1,2,3};
int main() {
fcn();
printf("HI\n");
}
stuff.h:
#ifndef STUFF
#define STUFF
extern int a;
extern int testarr[];
#endif
fcn.h:
#include "stuff.h"
extern int b[];
void fcn();
fcn.c:
#include "main.h"
int b[]={5,6,7};
void fcn() {
printf("Hello\n");
}
It is not clear why you are using so many global variables. The array
int testarr[]={1,2,3};
is defined as many times as there are compilation units (in your example there are at least two compilation units) that include the corresponding header.
Declare the array in a header like
extern int testarr[3];
and define it in a cpp module.
int testarr[]={1,2,3};
The same is valid for other global variables that have external linkage.
As for this remark
BTW, based on something else I found, I tried defining testarr as
extern but got the same problem.
Then the array with the specifier extern shall not be initialized in a header. Otherwise it is a definition of the array.

Proper way to declare and use structures in C project?

I am building a project that I am trying to organize as follows:
main.c
globals.h
structures.h
FunctionSet1.c, FunctionSet1.h
FunctionSet2.c, FunctionSet2.h
etc.
I thought I could define a structure type in structures.h:
struct type_struct1 {int a,b;}; // define type 'struct type_struct1'
then declare a function1() returning a structure of type type_struct1 in FunctionSet1.h:
#include "structures.h"
struct type_struct1 function1(); // declare function1() that returns a type 'struct type_struct1'
then write function1() in FunctionSet1.c:
#include "FunctionSet1.h"
struct type_struct1 function1() {
struct type_struct1 struct1; // declare struct1 as type 'struct type_struct1'
struct1.a=1;
struct1.b=2;
return struct1;
}
Edit: with the corrected code above, the compiler returns
306 'struct' tag redefined 'type_struct1' structures.h
Is the file set good practice ?
What is the good practice to manage the structures ?
In your example, you declare a structure named type_struct in structure.h, then in FunctionSet1.h the structure that you are returning is type_struct, and in the .c it is called struct1.
So i think that the problem is that struct1 and type_struct are not recognized because they have never been defined ...
However, the organization of your files is fine.
Your general structure looks good. One thing you need to do, as zenith mentioned, is to put include guards into your header files. What that is is a set of #define's that make sure that the contents of the header are not included more that once in a given file. For example:
structures.h:
#ifndef STRUCTURES_H
#define STRUCTURES_H
struct type_struct1{
int a,b;
};
...
// more structs
...
#endif
FunctionSet1.h:
#ifndef FUNCTION_SET_1_H
#define FUNCTION_SET_1_H
#include "structures.h"
struct type_struct1 function1();
...
// more functions in FucntionSet1.c
...
#endif
main.c:
#inlcude <stdio.h>
#include "structures.h"
#include "FunctionSet1.h"
int main(void)
{
struct type_struct1 struct1;
struct1 = function1();
return 0;
}
Here, main.c includes structures.h and FunctionSet1.h, but FunctionSet1.h also includes structures.h. Without the include guards, the contents of structures.h would appear twice in the resulting file after the preprocesser is done. This is probably why you're getting the "tag redefined" error.
The include guards prevent these type of errors from happening. Then you don't have to worry about whether or not a particular header file was included or not. This is particularly important if you're writing a library, where other users may not know the relationship between your header files.
First of all, you have to declare the structure in your file.h (you can use typedef to create an alias)
typedef struct Books
{
char title[50];
int book_id;
} books;
then, you have to include your file.h in your file.c and declare your variable like this
#include "file.h"
int main()
{
books book1;
book1.title = "Harry Potter";
book1.book_id = 54;
}
or like this if you didn't use typedef
#include "file.h"
int main()
{
struct Books book1;
book1.title = "Harry Potter";
book1.book_id = 54;
}
Thank you all.
I read again what you said and found that the code above is now correct.
The error I report is with testing the following main.c
#include "structures.h"
#include "FunctionSet1.h"
void main() {
struct type_struct1 struct2;
struct2=function1();
}
in which structures.h is included again, thus causing the error. Removing the include eliminates the error.
I will now look into header guards to avoid such problems.
Thanks again.

External Structs and Multiple Headers

I have a confusion about external structs. I have to define a global instance of the struct in a file other than which the struct is defined (as a RAM variable which I do not know what it is exactly).
Below is an example that GCC can compile and it runs correct while Code Composer Studio gives compile-time errors.
I want to learn where the problem is, how GCC can compile, and where/how I should use the extern declaration.
Any comment would be appreciated.
person.h
#ifndef PERSON_H
#define PERSON_H
struct person {
int age;
};
typedef struct person PERSON;
void modifyPerson();
#endif // PERSON_H
personRam.h
#ifndef PERSONRAM_H
#define PERSONRAM_H
#include "person.h"
PERSON p1;
#endif // PERSONRAM_H
modifyPerson.c
#include "person.h"
#include "personRam.h"
void modifyPerson() {
p1.age = 10;
}
main.c
#include <stdio.h>
#include "person.h"
#include "personRam.h"
int main() {
modifyPerson();
printf("%d", p1.age);
return 0;
}
You should not get a compiler error, but a linker error, saying that p1 is defined multiple times. At least that's what I guess is the problem.
The reason is that you define the variable in a header file, which you then include in multiple source files. This means that the definition is in both source files (The preprocessor #include directive literally puts the contents of the header file in place of the include "statement").
If you declare the variable as extern in the header file, and define it in one source file it should work.
So in personRam.h
extern PERSON p1;
And in one of the source files:
PERSON p1;
On which operating system are you compiling, and for which target system?
For what it is worth, Linux (& Unix-es) and Windows have different linking semantics.
Read Levine's "Linkers & Loaders" book for details.

Resources