Hello!
What a great question! The answer is a consequence of the facts that
- C++ has user name overloading (i.e. you can have more than one function named 'foo'),
- C does not have name overloading, and
- the linker need to know the difference between e.g. `void foo(int)` and `void foo(double)` from C++ code, and `void foo(int)` from C code, and allow them to coexist in the same program!
The details of the way this is done aren't terribly important to the normal answer ("name mangling"), but the *purpose* of the `extern "C" { ... }` construct is to tell the compiler that the user names declared within the curly braces are to be considered C-specific names, and not C++.
As to your specific question, "What exactly does putting `extern "C"` into C++ code do? For example: extern "C" { void foo(); }", you can see the effects in an example:
This code, compiled with g++ and the option to leave the assembly language, results in this:
Note that the name of the C++ function `void bar()` has become `__Z3barv` while the name of the C function `void foo()` has become `_foo`.
The C function name has an underscore prepended which, historically, was done to differentiate between assembler labels, and C-code labels. (Writers of assembler are/were encouraged to avoid starting labels with an "_".)
The C++ 'mangling' is used to be able to differentiate between the different possible foo's, and does so by encoding the signature of the function in the mangled name. The label `__Z3barv` preserves the text `bar` of the original symbol (the `3bar` part), but also says that the function (from the `__Z` part) has no arguments (from the `v` part). This way, this `bar()` can be differentiated from e.g. this one: `bar(int)`.