* A list of function signatures, data structures it provides, etc
* Any constant definition specific to the module
Another "feature" of separating the header file from the implementation is that it guards against recursive includes, as the commenter above suggested.
The header file should not have the includes that the implementation uses. It should have the minimal necessary to achieve its purposes as a header file.
It is leaking includes without any reason, there is no need for the user of given module to know what dependencies the implementation is using. Place to list dependencies is at the beginning of the source file of given module, and as far as I know this is the convention.
Main problem with dependencies in the headers is that if any header of your library include headers from the different libraries the user will have have to (1) have those headers, (2) probably configure their build to use them, even if they bring zero useful information for them.
They're not there for "no reason". For example, if I use a type defined in some external header, I definitely need to include that in the .h, so I might as well just include everything else.
Besides, in my mind it's the logical place to put it: the header file is almost like the "spec" or the "coversheet" of a .c. It includes the name, the authors, possibly a description of what it does, a list of functions and datatypes, so why not a list of dependencies as well?
The header role is to define the interface of the module, that's why I believe the leaner the header is the better. When I'm using a module I do not care what the implementation is using, the only thing I care about is what functions are exposed and what data structures are required by the functions. All other details are irrelevant. If any of the functions are using any types from the external header that are passed by value (for pointers forward declaration is the way to go), then that headers also become part of the interface and have to be #included in header.
For C, I'd say the biggest benefit is that you can absorb a clearer picture of how parts of your project are using other parts, because your .c files have to directly include the headers they use. It's not perfect, because you won't be perfectly disciplined and can't use pointer indirection for every single type, but it is often very useful if you can immediately see a short list of .c files that could possibly access the interface exposed by a particular header file.
Another reason is namespace pollution (if only for better autocomplete), and another is that you don't walk yourself into a situation where editing one header file suddenly gives you a zillion name lookup errors (because that's mildly annoying).
In C++, the biggest and most substantial benefit can be the effect on compile times.
>For C, I'd say the biggest benefit is that you can absorb a clearer picture of how parts of your project are using other parts, because your .c files have to directly include the headers they use.
It may just be that this is the specific way in which my mind works, but I find it easier to get a clearer picture of the file if I just read the .h. It would have a summary (in terms of comments and code, like function declarations) and a list of includes.
>it is often very useful if you can immediately see a short list of .c files that could possibly access the interface exposed by a particular header file.
If you wanted to see which files use the interface in that header file directly, you can scan your headers for ones that include it explicitly, instead of working backward from the header. And a similar thing with the autocomplete problem: only load the header files mentioned in thing.h (assuming you're editing thing.c).
The increased compilation time is a good argument. I don't know any good way to mitigate it, but all these three problems sound like engineering problems to me, rather than a problem intrinsic to this approach.
> If you wanted to see which files use the interface in that header file directly, you can scan your headers for ones that include it explicitly, instead of working backward from the header.
Your .c files that use the interface will often be including it implicitly though, projects very quickly drift in that direction.
He is referring to the lack of guards in your header files(#ifdef NAME, #define NAME, #endif). That will prevent the preprocessor to include the file twice so your compiler can be happy.