Multiple header & source files and its use

Thread Starter

Kittu20

Joined Oct 12, 2022
511
The primary advantage of multi-file programs is problem decomposition and modularity. What you put into a file and what you put into a function are two aspects of the same thing.
Suppose I have a big project in which I have written code for UART, SPI and I2C in single file. I can create separate header and source file for module

Something like
Code:
Uart.h
Uart.c
SPI.h
SPI.c
I2C.c
I2C.h
main.c
Will all header files be included in the main.c file?
or the header file for each model will be included in the their source file only?
 

WBahn

Joined Mar 31, 2012
32,908
Suppose I have a big project in which I have written code for UART, SPI and I2C in single file. I can create separate header and source file for module

Something like
Code:
Uart.h
Uart.c
SPI.h
SPI.c
I2C.c
I2C.h
main.c
Will all header files be included in the main.c file?
or the header file for each model will be included in the their source file only?
You include header files wherever they are needed. If you main uses functions or macros from all three, then you would include all three in main.c.

Remember, the purpose of the header file is to give the compiler enough information to compile the code in the file in which it gets included.
 

Thread Starter

Kittu20

Joined Oct 12, 2022
511
You include header files wherever they are needed. If you main uses functions or macros from all three, then you would include all three in main.c.

Remember, the purpose of the header file is to give the compiler enough information to compile the code in the file in which it gets included.
I get no error and warning when all header files included in one source file main.c
Code:
//main.c

#include<stdio.h>
#include"temp.h"
#include"math_operation.h"

int main()
{
   int array2[5] = { 1, 2, 1, 2, 5};
   Remove_duplicate_zero(array2, 5);
   printf("\n");
   addition(1, 2);  
 
   return 0;

}

// temp.h
void Remove_duplicate_zero( int array2[], int size);

//temp.c
#include<stdio.h>


void Print_Array( int array[], int size)
{
    for ( int i = 0; i < size; i++)
    {
        printf("%d ", array[i]);
    }
}

void Remove_duplicate_zero( int array2[], int size)
{
   int i = 0;
   int j = 0;

    for ( int i = 0; i < size; i ++)
    {
        for ( int j = i+1; j < size; j++)
        {
            if ( array2[i] == array2[j])
            {
                array2[j] =0;
            }
        }
    }
   Print_Array(array2, size);
}

//math_operation.h
void addition(int a, int b);

//math_operation.c
#include <stdio.h>

void addition(int a, int b) {
  int c;
  c = a + b;
  printf("sum = %d\n", c);
}
Output
Code:
1 2 0 0 5
sum = 3
why I get warning when I include each header file with their source files
main.c
C:
#include<stdio.h>

int main()
{
   int array2[5] = { 1, 2, 1, 2, 5};
   Remove_duplicate_zero(array2, 5);
   printf("\n");
   addition(1, 2);  
 
   return 0;

}
temp.h
C:
void Remove_duplicate_zero( int array2[], int size);
temp.c
C:
#include<stdio.h>
#include"temp.h"

void Print_Array( int array[], int size)
{
    for ( int i = 0; i < size; i++)
    {
        printf("%d ", array[i]);
    }
}

void Remove_duplicate_zero( int array2[], int size)
{
   int i = 0;
   int j = 0;

    for ( int i = 0; i < size; i ++)
    {
        for ( int j = i+1; j < size; j++)
        {
            if ( array2[i] == array2[j])
            {
                array2[j] =0;
            }
        }
    }
   Print_Array(array2, size);
}
math_operation.h
C:
void addition(int a, int b);
math_operation.c
C:
#include <stdio.h>
#include"math_operation.h"
void addition(int a, int b) {
  int c;
  c = a + b;
  printf("sum = %d\n", c);
}
output
Code:
main.c: In function 'main':
main.c:6:4: warning: implicit declaration of function 'Remove_duplicate_zero' [-Wimplicit-function-declaration]
    Remove_duplicate_zero(array2, 5);
    ^~~~~~~~~~~~~~~~~~~~~
main.c:8:4: warning: implicit declaration of function 'addition' [-Wimplicit-function-declaration]
    addition(1, 2);
    ^~~~~~~~
 

WBahn

Joined Mar 31, 2012
32,908
Think about it.

If you give the compiler your main.c, the compiler has to be able to compile the call to Remove_duplicate_zero() and the call to addition().

It can't do that because it has no idea what either of those functions need. How many arguments? What type of arguments? Is there a return value? If so, what type is the return value?

You need to include the two header files so that the compiler knows that information based on the prototypes in the headers. Otherwise, the compiler has to guess and it's guess will be to look at the function call and imply a prototype based on the arguments used. It will generally assume that the function returns an int.

Never ignore this warning -- doing so is a recipe for disaster.

Including the header file in the source file of the same name is usually not required, but it is almost always a good idea. The reason is that it ensures that the functions that are defined in the .c file match the calls where they get used. If you were to change your addition() function so that it took two doubles instead of two ints, for instance, it would compile just fine without the header inclusion, but it would not match the call in main(), which could corrupt the stack or give bogus results. But with the header inclusion, you'll get a warning about the redeclaration of the function.
 

Thread Starter

Kittu20

Joined Oct 12, 2022
511
It can't do that because it has no idea what either of those functions need. How many arguments? What type of arguments? Is there a return value? If so, what type is the return value?

You need to include the two header files so that the compiler knows that information based on the prototypes in the headers. Otherwise, the compiler has to guess and it's guess will be to look at the function call and imply a prototype based on the arguments used. It will generally assume that the function returns an int.
My plan is that there is a project which has many modules and i want to create header file and source file for each module.

I include multiple header file in one file main. c then i am not getting any problem.

I am having a problem when one header file is included in their source file.

Is my use case not correct to solve this problem?
 

WBahn

Joined Mar 31, 2012
32,908
My plan is that there is a project which has many modules and i want to create header file and source file for each module.

I include multiple header file in one file main. c then i am not getting any problem.

I am having a problem when one header file is included in their source file.

Is my use case not correct to solve this problem?
Again, think about it from the viewpoint of the compiler.

Imagine that you are going to give each one of your source files to a separate person and have them compile it for you. Whoever gets main.c has to be able to generate the code to CALL your addition() function and deal with whatever addtion() returns. To do this, they need to know how many and what type of arguments addition() is expecting and whether it returns a value and, if so, what type. They don't need to know anything else, just those things. That information is provided by a function prototype. The prototype is contained in your file math_operation.h. So you need to include that file at the top of your main.c so that the compiler has that prototype information when it compiles main.c because main.c contains a call to addition() and addition()'s prototype is located in math_operation.h.
 

dcbingaman

Joined Jun 30, 2021
1,065
Suppose I have a big project in which I have written code for UART, SPI and I2C in single file. I can create separate header and source file for module

Something like
Code:
Uart.h
Uart.c
SPI.h
SPI.c
I2C.c
I2C.h
main.c
Will all header files be included in the main.c file?
or the header file for each model will be included in the their source file only?
You only include the ones you actually need.
Like when you have a simple program that prints to the console you only need stdio.h. If you want to use the math functions you include math.h. If you want to work with strings you include string.h.

You may include headers you don't need. The compiler simply ignores them.

Your library is no different from the ANSI C standard libraries in that sense so just include what you are actually using.

Here is a list of most of the ANSI C library headers. There is a lot, which is why you only include the ones you actually need:

https://en.cppreference.com/w/c/header

Also, make sure you are not 're-inventing the wheel' as a lot of functionality is included in these standard libraries.
 

dcbingaman

Joined Jun 30, 2021
1,065
Suppose I have a big project in which I have written code for UART, SPI and I2C in single file. I can create separate header and source file for module

Something like
Code:
Uart.h
Uart.c
SPI.h
SPI.c
I2C.c
I2C.h
main.c
Will all header files be included in the main.c file?
or the header file for each model will be included in the their source file only?
In this situation I would not directly include low level interfaces such as UART/SPI etc. in the top level application code (that is main.c).

Here is an example of what I mean. Say you have one I2C device that happens to be a temperature sensor monitoring ambient room temperature. You need to read the temperature from the sensor. I would make another module called say AmbientTemperature.h/c. In the c file for that module, I would include I2C.h and create a function maybe like:

double AmbientTemperature_GetReading();

This function has the required I2C commands specific to the sensor to handle getting it's temperature.

That would then be included in main.c

Why all this complication? Imagine later during your project the board developers decide to not use the I2C chip but instead want to use say a SPI chip to get the temperature. With the middle library, there is zero changes that need to be made to main.c. You just create another AmbientTemperature.c module for getting the temperature from the new device, switch it out and leave the original AmbientTemperature.h file unchanged and you are finished. But without it you have to go back in and change main.c. You want to keep changes to a minimum so you maximize abstraction.

Example for the UART. The UART normally is talking to something, say a personal computer that reads data from the microcontroller, in that case you have another layer called say PCCommunications.h/c. That may have an interface like:

int PCCommunications_ACommandHasBeenReceived();
int PCCommunications_ReadCommand_Length();
void PCCommunicationsReadCommand(char* cmd,int length);
etc...

Again, if the PC interface changes but the commands stay the same there is significantly less work to do when updating your software.

Another benefit: It is easier to write unit tests for testing these interfaces as they exist in their own modules.
 
Last edited:
Top