The program is valid as written, but def.c is required to ensure that the code always works with all compilers and any combination of optimization levels for different files.
Since it has an extern declaration, def.c provides an external definition of the foo() function, which you can confirm with nm :
$ nm def.o 0000000000000000 T foo
This definition will always be present in def.o no matter how this file is compiled.
use.c has a built-in definition of foo() , but according to 6.7.4, the C standard does not define whether the call foo() uses this built-in definition or uses an external definition (in practice, it uses a built-in definition, depending on whether the file is optimized or not). If the compiler decides to use the built-in definition, it will work. If he does not want to use the built-in definition (for example, because it is compiled without optimizations), you need an external definition in some other file.
Without optimization, use.o has an undefined link:
$ gcc -std=c99 -pedantic -Wall -Wextra -c -o use.o use.c $ nm use.o 0000000000000000 T bar U foo
But with optimization this is not the case:
$ gcc -std=c99 -pedantic -Wall -Wextra -c -o use.o use.c -O3 $ nm use.o 0000000000000000 T bar
There will be a definition of foo() in main.cpp , but it usually generates a weak character, so it may not be supported by the linker if another definition is found in another object. If a weak character exists, it can satisfy any possible reference in use.o , which requires an external definition, but if the compiler encloses foo() in main.o , then it cannot emit any definition of foo() in main.o , and therefore the definition in def.o is still necessary to satisfy use.o
Without optimization, main.o contains a weak character:
$ g++ -std=c++11 -pedantic -Wall -Wextra -c -o main.o main.cpp $ nm main.o U bar 0000000000000000 W foo 0000000000000000 T main U printf
However, compiling main.cpp with -O3 calls foo , and the compiler does not allocate any character for it:
$ g++ -std=c++11 -pedantic -Wall -Wextra -c -o main.o main.cpp -O3 $ nm main.o U bar 0000000000000000 T main U printf
So, if foo() not enclosed in use.o , but is in main.o , then you need an external definition in def.o
Will it work if def.c was deleted and foo was not used in C?
Yes. If foo used only in a C ++ file, you do not need the external definition of foo in def.o , because main.o either contains its own (weak) definition or embeds a function. The definition in foo.o is only necessary to satisfy the unconfigured calls to foo from another C code.
In addition, the C ++ compiler is allowed to generate any character for foo when optimizing main.o , because the C ++ standard says that the declared inline function in one translation unit must be declared built-in in all translation units and to call the declared function inline definition must be available in the same file as the call. This means that the compiler knows that if some other file wants to call foo() , then this other file must contain the definition of foo() , and therefore, when this other file is compiled, the compiler will be able to generate another weak definition of the function symbol ( or embed it) as needed. Therefore, there is no need to output foo to main.o if all calls to main.o have been nested.
This is the differnet semantics from C, where the built-in definition in use.c can be ignored by the compiler, and the external definition in def.o must exist even if nothing in def.c calls it.