0

Assuming we have 2 files DIO.c and DIO.h. I used to #include all necessary header files in DIO.h and only #include DIO.h in DIO.c. while working on drivers for ATmega32, I found out that some functions are declared implicitly while including other modules. This made me wonder is that right to include all files in header file instead of source file? and how what i'm doing currently affects dependency?

After visiting some repos on github i found out that they never #include anything in header files, and only include everything in C file, which made me more confused about what about typedefs? how they use them without including the header file containing them?

Here is an example of DIO.h file:

#include "Dio_Private.h"
#include "Dio_Config.h"
#include "../../Utilities/Macros.h"

and here is an example of DIO.c file:

#include "DIO.h"

If the answer was that I should include all header files in C file, what about enums?

for example, if I want to use enums defined in DIO.h file in any other module, should I now seperate these enums in another header file and only #include it?

Thanks in advance :)

7
  • 2
    My opinion is that you should include what you use where you use it. If one of the includes in a header is removed because it it no longer necessary it shouldn't break the program because the source files include what they use explicitly. Commented Jan 28, 2023 at 18:49
  • 2
    Only include what you need. Header files in particular should be conservative about polluting their user’s name spaces. I always design header files to include only the bare minimum necessary to support the API described in the header file. Commented Jan 28, 2023 at 19:10
  • This is a style question, with opinions on both sides. See question 10.7 in the C FAQ list for some of the arguments. Commented Jan 29, 2023 at 13:59
  • If Dio.h is exporting an interface of certain Dio-functions, what are Dio_Private.h and utilities/Macros.h .. what are you writing then Dio.c for? Worst thing is, that such definitions then through header include hierarchies are visible in higher layers and even clash there with other names. Commented Jan 29, 2023 at 16:14
  • 1
    @NabilYasser, These macros and HW register definitions have no place to be included within Dio.h, if Dio.c is actually implementing the HW access. Like AUTOSAR Dio, there are maybe just 2 function Dio_LevelType Dio_ReadChannel(Dio_ChannelType chn); and void Dio_WriteChannel(Dio_ChannelType chn, Dio_LevelType lvl); in the header, plus a Dio_Cgh.h include defining the channel IDs. The rest is handled in the Dio.c file. No Set/ClrBit macros, no HW registers outside Dio. Commented Jan 29, 2023 at 23:32

3 Answers 3

2

It's perfectly fine to #include multiple headers in one and use that (provided you use proper include guards).

Having said that, if you don't like typing multiple #includes over and over and you are thinking of creating a big one just for convenience, keep in mind that this will affect compilation time (since the contents of all the headers have to be parsed for every .c file that includes them).

Sign up to request clarification or add additional context in comments.

Comments

2

@ShaneGervais is right that you should use include guards, and right that #include is somewhat like pasting the contents of the header file into your source file, but incorrect about the rest of it.

Example Dio_Private.h

#ifndef DIO_PRIVATE_H_
#define DIO_PRIVATE_H_

int dinput(char **);

int doutput(char *);

#endif

This will ensure no errors on multiple #include

Do not use #pragma once. Do not use #define __DIO_PRIVATE_H__. These are not standard C and the latter one results in undefined behavior.

Do not define your functions in a header file, especially as a beginner. For very small, very succinct functions that do not use global variables and which will not bloat your code too much if used several times over, it may be appropriate, when you more fully understand how to use them, to define them in a header file. Example:

#ifndef MYSTRDUP_H_
#define MYSTRDUP_H_

#include <stdlib.h>
#include <string.h>

static inline char *mystrdup(const char *s) {
    size_t n = strlen(s) + 1;
    char *r = malloc(n);
    if (r) memcpy(r, s, n);
    return r;
}
#endif

4 Comments

Using #pragma once does not “violate” the C standard. It is not fully portable but must be ignored by implementations that do not recognize it, per C 2018 6.10.6 1.
@EricPostpischil: Very well, I softened the language. By C 2018, you mean the version of C for which __STDC_VERSION__ is defined as 201710L? :-P
By “C 2018,” I mean the C standard published in 2018, ISO/IEC 9899:2018(E), which specifies that __STDC_VERSION__ is defined by conforming implementations to be the integer constant 201710L.
(Of course, I noted reserved identifiers but then used strdup() as an example of a static inline function. Fixed.)
1

This question is a matter of opinion and style, and therefore probably not regarded as a "good" question for SO. I can offer advice only:

  • Include anything in the header file necessary to make the header file valid without requiring additional includes.

So for example if header file xxx.h references a symbol such as int32_t, then it should explicitly include stdint.h. Otherwise the user of the header file will have to "know" that stdint.h is required to be included before xxx.h, even if the subsequent source never references stdint.h type or symbols.

To not allow nested includes is a nonsense, because the user of a header file will have to know or work out what include dependencies are required and they cold be very many.

On the other hand to include headers for symbols not referenced in the header itself pulls in interfaces the user might not expect and is inefficient. You might do that when a public interface is a collation or parts in multiple headers, but you need ot be able to justify it and follow the principles of maximum cohesion, minimal coupling.

After visiting some repos on github ...

I would not assume some randomly selected repo to be definitive or even good practice or the arbiter of such. Being published on Github is not an indication of quality - it is a poor strategy to learning good coding style. You might better take your "best-practice" cues from standard or device library headers for example.

4 Comments

Thanks a lot for your answer, but there is some core info I want to know about this. If I included all DIO driver @ MCAL headers in Dio_Interface.h and included this in Led_Interface.h @ HAL, and finally included Led_Interface.h in App.h @ Appl Layer now all functions of DIO driver will appear in Application layer which isn't supposed to be, in my opinion. so, as a rule of thumb, what makes sense for this specific topic? since I just knew you're an embedded SW engineer.
+1. This is good advice. Header files should present the public interface of a code module and thus provide everything that is needed to use the functionality of that module - and nothing more.
@NabilYasser Is it necessary for Dio_Interface.h to have all "DIO driver @ MCAL" headers included? You should only include those headers which are necessary for the definitions in the header file itself. The .c file should then include the additional headers it needs for the implementation.
@NabilYasser That probably deserves posting a s a new question where you can provide a clear example and an answer can be provided. Comments are not for run-on questions or discussion. If DIO is not referenced in the public interface of LED, it need not be included.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.