TL/DR: Your compiler / linkeditor is finding the dependencies you included (e. g., stdlib.h
) in some library in the default path. According to compile/ linkedit options, the library is being included dynamically or statically.
Your question has a simple answer, but it is not possible to talk about what happens without reviewing a number of concepts:
Dynamic vs static libraries
C / C++ libraries can be statically or dynamically linked.
In a coarse simplification, static linkediting produces an independent executable with a copy of the library; that is, you end up with a larger executable containing the binary of your application and the library. If you need to change the library you will have to recompile your application to include the new changes.
In contrast, dynamic linkediting produces independent artifacts. A shared library (usually .so
in systems *NIX and .dll
in Windows) is press load time or run time. Roughly the application that references a dynamic library contains a "symbol table" indicating external dependencies, when any of these dependencies (e.g., any function) is requested it is "loaded in memory" (the details of the "algorithm" that determines how and which library should be "loaded" are complex, I don’t want to get into that merit).
The advantage of dynamic libraries is that a single library can be shared between multiple executables; additionally libraries can also be upgraded independently (provided binary compatibility is maintained). The downside is that complex projects can end up with a deep dependency graph, creating all kinds of problems (version incompatibility, accidental inclusion of legacy library versions, need to do backport of cool security for legacy versions, etc, etc, etc).
Templates
In addition to prototypes of functions, structs, classes and enumerations (part of the "signature / interface" of a given library), templates are included in the headers. At compile time / linkediting specific versions of the parameterized constructions are generated (e.g., a version with int
and another with float
of a function template) embedded in the application binary. That’s why in some compilers the size of the binary grows significantly when you use, for example, the Std.
How linkeditor finds a library
How does your linkeditor find a library? Roughly it does a search on path (path) where libraries are available. The answer from @pmg mentions the libc
; linkeditor can find an implementation like libc.so
or msvcrt.lib
in a multitude of places by a multitude of rules (flags passed to the linkeditor, environment variables such as LD_LIBRARY_PATH
, standard directories as /usr/lib
, current application directory, etc, etc, etc.). The rules usually vary with the operating system and the stack of build.
So what really happens when I include libraries like stdlib.h
, iostream
, etc.?
In sufficiently complex applications, the required libraries are localized and there is a combination of dynamic and static linkage as well as instantiation / template expansion.
While most compilers will, by default, do their best to dynamically link libraries, a portion of the library code ends up being directly or indirectly copied / expanded within the executable.
Linkeditors are usually able to report everything that has been statically and dynamically linked (e. g., gcc -Wl --verbose
). Additionally, tools such as ldd
and Dependency Walker can list dependencies.