In C, if you define a function in a header file, then that function will appear in each module that is compiled that includes that header file, and a public symbol will be exported for the function. So if function additup
is defined in header.h
, and foo.c
and bar.c
both include header.h
, then foo.o
and bar.o
will both include copies of additup
.
When you go to link those two object files together, the linker will see that the symbol additup
is defined more than once, and won't allow it.
If you declare the function to be static, then no symbol will be exported. The object files foo.o and bar.o will still both contain separate copies of the code for the function, and they will be able to use them, but the linker won't be able to see any copy of the function, so it won't complain. Of course, no other module will be able to see the function, either. And your program will be bloated up with two identical copies of the same function.
If you only declare the function in the header file, but do not define it, and then define it in just one module, then the linker will see one copy of the function, and every module in your program will be able to see it and use it. And your compiled program will contain just one copy of the function.
So, you can have the function definition in the header file in C, it's just bad style, bad form, and an all-around bad idea.
(By "declare", I mean provide a function prototype without a body; by "define" I mean provide the actual code of the function body; this is standard C terminology.)
This is one of those "should" rather than "shall" kinds of coding standards. The reason is that you would pretty much have to write a C++ parser to enforce it.
A very common rule for header files is that they must stand by themselves. A header file must not require that some other header files be #included before including the header in question. This is a testable requirement. Given some random header foo.hh
, the following should compile and run:
#include "foo.hh"
int main () {
return 0;
}
This rule has consequences with regard to use of other classes in some header. Sometimes those consequences can be avoided by forward declaring those other classes. This isn't possible with a lot of the standard library classes. There's no way to forward declare a template instantiation such as std::string
or std::vector<SomeType>
. You have to #include
those STL headers in the header even if the only use of the type is as an argument to a function.
Another problem is with stuff that you incidentally drag in. Example: consider the following:
file foo.cc:
#include "foo.hh"
#include "bar.hh"
void Foo::Foo () : bar() { /* body elided */ }
void Foo::do_something (int item) {
...
bar.add_item (item);
...
}
Here bar
is a class Foo
data member that is of type Bar
. You've done the right thing here and have #included bar.hh even though that would have to have been included in the header that defines class Foo
. However, you haven't included the stuff used by Bar::Bar()
and Bar::add_item(int)
. There are many cases where these calls can result in additional external references.
If you analyze foo.o
with a tool such as nm
, it will appear that the functions in foo.cc
are calling all kinds of stuff for which you haven't done the appropriate #include
. So should you add #include
directives for those incidental external references foo.cc
? The answer is absolutely not. The problem is that it is very hard to distinguish those functions that are called incidentally from the ones that are called directly.
Best Answer
They can, as shown by new languages that do.
But a design decision was made all those years ago (when the C compiler was multiple independent stages) and now to maintain compatibility the pre-processor has to act in a certain way to make sure old code compiles as expected.
As C++ inherits the way it processes header files from C it maintained the same techniques. We are supporting a old design decision. But changing the way it works is too risky lots of code could potentially break. So now we have to teach new users of the language how to use include guards.
There are a couple of tricks with header files were you deliberately include it multiple times (this does actually provide a useful feature). Though if we redesigned the paradigm from scratch we could make this the non-default way to include files.