Many people have told me that usually in an .h are stored function prototypes, macros, variables. but what if you saved the content of a function? Would it be a bad practice? Would there be a problem at compile time?
Many people have told me that usually in an .h are stored function prototypes, macros, variables. but what if you saved the content of a function? Would it be a bad practice? Would there be a problem at compile time?
Interesting question. I personally consider it a good programming practice to implement the body of the functions in the files with the .c extension. As you indicate, the file with the .h extension would be intended for function prototypes, macros and includes. I learned C after getting started with Javascript and then learning Java. At least, in my case, respecting the distinction between .h and .c files makes programming in C "as close as possible" to object-oriented programming, i.e. having interfaces (what a .h file would be) and classes (what would be a .c file). But finally, like everything, it is possible to do it, everyone decides according to their preferences.
C does not distinguish between declarations and implementations. This is a distinction that we make for several reasons:
Compilation time: Every time a header is modified (however small the change), all the files that include that header must be recompiled, as well as the files that include them. In other words, modifying a header causes a domino effect that can force a large part of a project to be recompiled. What tends to change the most in a code is usually the implementation, then by isolating it from the header we manage to reduce the number of files to be recompiled.
Code Hiding: Developing an algorithm can be an investment of time and money. Cheerfully exposing your hard-earned source code may not be the preferred option for someone looking to monetize it. While compiled code can be reverse-engineered, it offers more protection than simply presenting the source code in the form of headers.
Isolation: Separating the header from the implementation makes it easier to create interfaces. An interface is nothing more than a kind of contract. Basically it tells you what can be done with a library, what happens behind it is transparent to the client. This architecture allows entire implementations to be replaced with completely different ones without the customers having to know.
Of course, having the implementation in the header also has its advantages:
If the compiler has a function implementation at its disposal, it can perfectly replace the call to the function with its code... in the case of simple functions that are constantly called, this small change can be a significant improvement.
When programming libraries, having the implementation in the headers allows you to have code that can be configured according to the needs of the library client. In this case the implementation usually has precompiler directives. Precompiled code in a static or dynamic library does not allow this configuration.
Which is the best option? It depends on the needs of the project and the tastes of the programmer / development team.
Based on what was said in the previous section, it depends.
Abuse of it could be considered a bad practice, but judging it without knowing the specific details that led to the decision on the design is taking too much risk.
As I have already mentioned, yes. Each change in the implementation will modify a header that will force to recompile in a recursive way all the dependent files, directly or indirectly, of said header.
It's easy to see with an example:
oh
bh
B.cpp
ch
c.cpp
After all this work we realize that the function
A.h
is wrong. The function has to return a product, not a sum... well, changing that symbol will force all files to be recompiled, even if your code doesn't use the affected function.In projects with thousands of files, choosing a good design can mean the difference between a minor change and spending half an hour (or more) recompiling files.