Search code examples
ctypeslinkage

Why don't structures in headers violate ODR across multiple translation units?


From what I understand, the main reason people separate function declarations and definitions is so that the functions can be used in multiple compilation units. So then I was wondering, what's the point of violating DRY this way, if structures don't have prototypes and would still cause ODR problems across compilation units? I decided to try and define a structure twice using a header across two compilation units, and then combining them, but the code compiled without any errors.

Here is what I did:

main.c:

#include "test.h"

int main() {
    return 0;
}

a.c:

#include "test.h"

test.h:

#ifndef TEST_INCLUDED
#define TEST_INCLUDED

struct test {
    int a;
};

#endif

Then I ran the following gcc commands.

gcc -c a.c
gcc -c main.c
gcc -o final a.o main.o

Why does the above work and not give an error?


Solution

  • C's one definition rule (C17 6.9p5) applies to the definition of a function or an object (i.e. a variable). struct test { int a; }; does not define any object; rather, it declares the identifier test as a tag of the corresponding struct type (6.7.2.3 p7). This declaration is local to the current translation unit (i.e. source file) and it is perfectly fine to have it in several translation units. For that matter, you can even declare the same identifier as a tag for different types in different source files, or in different scopes, so that struct test is an entirely different type in one file / function / block than another. It would probably be confusing, but legal.

    If you actually defined an object in test.h, e.g. struct test my_test = { 42 };, then you would be violating the one definition rule, and the behavior of your program would be undefined. (But that does not necessarily mean you will get an error message; multiple definitions are handled in various different ways by different implementations.)