As i see it, if the code in a file relies on other stuff to be declared, it should include the file that contains those declarations. Otherwise, stuff gets brittle and includes have to be done all the time and in a certain order, and it all gets ugly. So to me, the "duplicate includes" are a good thing; each piece of the code can take care of its own dependencies with less hassle.
As for how to keep things from breaking on duplicate includes...there's an idiom called "include guards". They look a little something like this...
(file1.h)
#ifndef FILE1_H
#define FILE1_H
(the meat of file1.h goes in here)
#endif
When this file is included the first time, FILE1_H
isn't defined yet (or shouldn't be, assuming you pick better names for your files than this), so the code gets included (and FILE1_H
subsequently gets defined). The next time it's included, though, FILE1_H
is now defined, so the code gets skipped.
(By the way, any macro name will work for this, as long as it's unique per file. But that particular constraint is the biggest reason the macro's name is almost always based on the file name.)
On most compilers, #pragma once
works as well. But it's not standard; if you care about being able to use any compiler you want, then don't use it (or use it in addition to the include guard).