Duplicate declarations aren't a problem; duplicate (type) definitions are. If the bar.h
header contained, for example:
enum FooBar { FOO, BAR, BAZ, QUX };
then including that twice in a single TU (translation unit — source file plus included headers) would give an error in general.
Also, the multiple inclusion scenario isn't what you show. What might cause the trouble is the following, assuming that there are no header guards in the header files:
bar.h
enum FooBar { FOO, BAR, BAZ, QUX };
void somefunc(char str[]);
quack.h
#include "bar.h"
extern enum FooBar foobar_translate(const char *str);
main.c
#include "bar.h"
#include "quack.h"
…
Note that GCC has an option -Wredundant-decls
to identify redundant declarations — where the same declaration is present several times (normally from multiple files, but also if the same declaration is present twice in a single file).
Prior to C11, you could not repeat a typedef
(at file scope; you always could hide an outer typedef
in a block scope). C11 relaxes that constraint:
§6.7 Declarations
¶3 If an identifier has no linkage, there shall be no more than one declaration of the identifier
(in a declarator or type specifier) with the same scope and in the same name space, except
that:
- a typedef name may be redefined to denote the same type as it currently does,
provided that type is not a variably modified type;
- tags may be redeclared as specified in 6.7.2.3.
However, you still can't define a structure type twice in a single scope of a TU, so notations such as:
typedef struct StructTag { … } StructTag;
must be protected with header guards. You don't have this problem if you use opaque (incomplete) types:
typedef struct StructTag StructTag;
As to why you can include standard headers, that's because the standard requires that you can:
§7.1.2 Standard headers
¶4 Standard headers may be included in any order; each may be included more than once in
a given scope, with no effect different from being included only once, except that the
effect of including <assert.h>
depends on the definition of NDEBUG
(see 7.2). If
used, a header shall be included outside of any external declaration or definition, and it
shall first be included before the first reference to any of the functions or objects it
declares, or to any of the types or macros it defines. However, if an identifier is declared
or defined in more than one header, the second and subsequent associated headers may be
included after the initial reference to the identifier. The program shall not have any
macros with names lexically identical to keywords currently defined prior to the inclusion
of the header or when any macro defined in the header is expanded.
Using header guards allows you to make your headers meet the same standard that the standard headers meet.
See also other diatribes (answers) on the general subject, including: