0

The rule in C against declaring a struct's members more than once seems to me to be the main reason that include guards are necessary. If we have the following in "header.h":

struct s {
    int a;
    char b;
};

and the file "a.h" #include's header.h, then we cannot include both "a.h" and "header.h" as then struct s is defined twice.

My question is, what is the problem with doing this? Why can't multiple identical definitions of structs be allowed? This would remove the need for include guards, and clean up C header files enormously.

The rule in C is that multiple declarations are allowed, but only one definition. For some reason, specifying the members of a struct is called "definition", even though it is not defining a variable or a function.

Gavin Smith
  • 3,076
  • 1
  • 19
  • 25

3 Answers3

1

Re-defining a structure is extremely error-prone. Even in your simple example, if a.h includes a #pragma that adjusts structure packing or alignment before it includes "header.h", then the two definitions may not necessarily be the same any longer. This type of problem would be hard to debug because it would be dependent on the header include order.

In general, there are a number of things that can go wrong when you allow data type re-definition. In exchange, you don't get any real benefits from it other than being able to drop the header guards. Header guards solve the problem and are only a minor level of overhead that doesn't clutter the code unreasonably. Some compilers support a #pragma once (or similar) that acts as an include guard but only requires one line of code.

In my personal opinion, it would be a better idea to guard against multiple inclusion by default and require guard macros only on headers that are designed to be included multiple times (leave the overhead to the use case that is in the vast minority). That's not the way C was originally implemented, though (plus it would make the pre-processor more complicated), so it's extremely unlikely that it will ever change.

bta
  • 43,959
  • 6
  • 69
  • 99
  • Structure packing options are something I hadn't considered. If preprocessor declarations in header files (such as "#pragma pack") take effect outside the header file, it could be hard to track down why two seemingly identical definitions are different, and the compiler might not even tell you they are different. The obvious solution to this would be to make such declarations last only for one source file, but this wouldn't be backwards compatible. – Gavin Smith Apr 25 '12 at 18:30
  • I think "backwards compatible" is the key issue here. C has behaved like this from the beginning, and it's something we've learned to live with. Changing it would be nice, but it would break so much existing code that it will never happen. If you look at languages that are younger than C, you'll find that many of them implemented their `#include` analogue to address annoyances found in C (see `#import` in Objective C, or `require` in Ruby). – bta Apr 25 '12 at 21:35
  • I'd say "that's not a bug--that's a feature". If varying the sequence of `#include` directives would alter the semantics of a `struct` definition, it would be better to have a struct get defined more than once, with the repeated definition causing an error *if and only if the resulting structure wouldn't match the original*, than have the second definition get skipped because of an include guard. – supercat Jun 13 '12 at 23:53
0

Well, it's like C works... It's definition because it provides the actual implementation of the object.

md5
  • 23,373
  • 3
  • 44
  • 93
0

You can't define them twice, because as @Kirilenko said, the definition is providing the implementation of the object. However, I am wondering if your question is also asking something else.

Edit: Change instantiation to definition.

Your definition of s

struct s {
    int a;
    char b;
};

would go into a .c file, or at least you would either extern the struct in a .h file and put the structure instantiation in a .c file, or use typedef in the .h file.

typedef struct s {
    int a;
    char b;
} my_struct_type;

Even if you wanted the struct defined in a .h file, you could prevent its "being defined twice" by bracketing like so

Edit: Removed underscores from macro #ifdef MY_STRUCT_DEFINED struct s { int a; char b; }; #endif

octopusgrabbus
  • 10,555
  • 15
  • 68
  • 131
  • Lose the leading underscores on the macro name. They are reserved. – R.. GitHub STOP HELPING ICE Apr 25 '12 at 17:53
  • Thanks. They're reserved in C? I'll take note of it, and edit the answer to remove the guards. – octopusgrabbus Apr 25 '12 at 17:55
  • Yes. Informally speaking, they're reserved for the system headers to use so they don't clash with your application macros and your application macros don't clash with the system headers. – R.. GitHub STOP HELPING ICE Apr 25 '12 at 17:55
  • This is not "instantiation". The struct type is being defined, but no variable of this type is being defined. The definition will needed in the header file if the source file including defines any variables of that type, as opposed to pointers to variables of that type. It will also be needed if the code needs to refer to struct members. – Gavin Smith Apr 25 '12 at 18:38