To answer this question, one has to delve into compilation process and what is needed in each part (question why these steps are perfomed is more historical, going back to beginning of C before it's standardization)
C and C++ programs are compiled in multiple steps:
- Preprocessing
- Compilation
- Linkage
Preprocessing is everything that starts with #
, it's not really important here.
Compilation is performed on each and every translation unit (typically a single .c
or .cpp
file plus the headers it includes). Compiler takes one translation unit at a time, reads it and produces an internal list of classes and their members, and then assembly code of each function in given unit (basing on the structures list). If a function call is not inlined (e.g. it is defined in different TU), compiler produces a "link" - "please insert function X here" for the linker to read.
Then linker takes all of the compiled translation units and merges them into one binary, substituting all the links specified by compiler.
Now, what is needed at each phase?
For compilation phase, you need the
- definition of every class used in this file - compiler needs to know the size and offset of each class member to produce assembly
- declaration of every function used in this file - to produce those "links".
Since function definitions are not needed for producing assembly (as long as they are compiled somewhere), they are not needed in compilation phase, only in linking phase.
To sum up:
One Definition Rule is there to protect programmers from theselves. If they'd accidentally define a function twice, linker will notice that and executable is not produced.
However, class definitions are required in every translation unit, and therefore such a rule cannot be set up for them. Since it cannot be forced by language, programmers have to be responsible beings and not define the same class in different ways.
ODR has also other limitations, e.g. you have to define template functions (or template class methods) in header files. You can also take the responsibility and say to the compiler "Every definition of this function will be the same, trust me dude" and make the function inline
.
class
/struct
definitions are not functions. They are types. The ODR rule applies to functions and objects, not types. – Previse#include
directive reads a file and copies the whole content directly at place of this directive. By using header file, you get a copy of this struct definition in every file thatinclude
s this header. – Aciculaclass
/struct
s available in multiple source files. – Previse{};
afterclass
/struct
keyword and a name. – Acicula.c
file) separately. So the compiler won't "remember" thatmain
is defined in1.c
when it's compiling2.c
. And the linker doesn't see the source code ofmain
, so it doesn't know that those two definitions are identical. So if the linker sees duplicate symbols, it throws an error. – Passstatic
, the functions are visible to compilation units, while the structs aren't. – Saccharo