Java programs, particularly large ones, are usually built in a modular fashion that supports code re-use. The source code is spread over several source files (.java), and is used to generate Java byte-code in class files (.class) which are identified by the class they represent, so in Java, there is a direct relationship between the name of a class and the file containing the code for that class. These are combined at run-time to produce the executing program. Java's standard library of utilities for file access, GUIs, internationalisation, etc, is a practical example of such modular programming.

A large C program may also be split into several source files (usually with a .c extension), and separate compilation of each of these produces an object file of (usually) the same name with a different extension (.o or .obj). These are the modules of C that can be combined to form an executable program. An object file contains named representations of the functions and global data defined in its source file, and allows them to refer to other functions and data by name, even if in a separate module. In C, there doesn't have to be any relationship between the names of functions and variables and the names of the modules that contain them.

A final executable program is produced by supplying all the relevant modules (as object files) to a linker (which is often built into the compiler). This attempts to resolve all the referred names into the memory addresses required by the generated machine code, and linking will fail if some names cannot be resolved, or if there are two representations of the same name.

For example, the object file generated from the code below would contain references to the names pow (because it is invoked as a function) and errno (because it is accessed as a global variable). The file would also provide a representation of the name func (because the source contains a definition of that function).

extern int errno;

void func(void)
{
  double pow(double, double);
  double x = 3.0, y = 12.7, r;
  int e;

  r = pow(x, y);
  e = errno;

  /* ... */
}

Like Java, C comes with a standard library of general-purpose support routines, an implementation of which is supplied with your compiler. Its source code is not usually required, since it has already been compiled into object files for your system, and these will be used automatically when linking.

Other pre-compiled libraries may also exist (e.g. to support sockets), but it will normally be necessary to link with them explicitly to use them.

Here is an illustration of a program built from several components:

The source code consists of four source files (foo.c, bar.c, baz.c, quux.c) and three header files for preprocessing ("yan.h", "tan.h", "tither.h"; see File inclusion). The program also uses some header files (<wibble.h>, <wobble.h>) from an additional library. Compiling each of the source files in turn generates the object files foo.o, bar.o, baz.o, quux.o, and these are linked with an archive of pre-compiled objects (libwubble.a) from the library to produce an executable program myprog.