C File Documentation


Summary

A C Source Code File is human-readable source code written in the C programming language, the text a programmer writes that a compiler turns into a runnable program. It is plain text with the MIME type text/x-csrc, so any editor opens it. To build it into a program you need a C compiler such as GCC, Clang or MSVC, for example gcc hello.c -o hello. A .c file does nothing by itself until it is compiled and linked with its headers and any other source files.

Technical details

FeatureValue
Full nameC Source Code File
File extension.c
MIME typetext/x-csrc
Format typePlain-text programming source code
LanguageC
DeveloperDennis Ritchie, Bell Labs; standardised by ANSI / ISO/IEC
Introduced1972 (C language); ANSI C 1989, ISO C 1990, latest C23
Open standardYes — ISO/IEC standardised language, plain text
EncodingASCII / UTF-8 text (optional UTF-8 BOM EF BB BF)
Magic numberNone — identified by content, not bytes
Entry pointmain() function
Companion filesHeader files (.h) declaring shared functions and types
CompilersGCC, Clang/LLVM, Microsoft MSVC
Build outputObject file, then linked executable (.exe on Windows)
Build systemsMake, CMake, Ninja
Free editors/IDEsVS Code, Visual Studio, Notepad++, Vim, Xcode, Code::Blocks
Related extensions.h, .cpp, .cc, .cxx, .hpp, .m
Specificationiso.org (ISO/IEC 9899, C23)
Structure at a glance

A .c file is plain ASCII or UTF-8 text with no magic signature (an optional UTF-8 byte-order mark EF BB BF may appear at offset 0 but is not required). It is identified by content, which typically starts with comments (/* ... */ or //) and #include preprocessor directives such as #include <stdio.h>, followed by function definitions. Execution of a compiled C program begins at the main() function. The file is source, not a program: a compiler must translate it before anything runs.

What is a .c file?

A .c file holds source code written in the C programming language, one of the oldest and most influential languages, created by Dennis Ritchie at Bell Labs around 1972 and later standardised as ANSI C in 1989, ISO C in 1990, and through to C23. It is plain text: a sequence of #include directives, function definitions, statements and comments that a human writes and reads. C underpins operating-system kernels, embedded firmware, databases and the runtimes of many higher-level languages, so .c files are everywhere in systems programming.

The single most important fact about the format is that a .c file is source, not a program. It cannot run on its own. A compiler translates the text into machine code, producing an executable, and only that executable runs. The rest of this article follows one .c file from text to running program: how the preprocessor, the translation unit, the compiler and the linker each transform it, and where main() fits in.

Anatomy of a C source file

A minimal but complete C file shows the parts every source file is built from.

#include <stdio.h>        /* preprocessor directive: pull in a header */

#define GREETING "Hello, world"   /* object-like macro */

int main(void)            /* the program's entry point */
{
    printf("%s\n", GREETING);
    return 0;             /* exit status handed back to the OS */
}

The #include and #define lines are preprocessor directives, handled before compilation. int main(void) is a function definition, and main is special: it is the entry point where execution begins. The printf call works only because <stdio.h> declared printf earlier, so the compiler knows its signature. The return 0 hands an exit status back to the operating system, where zero conventionally means success. Comments in /* ... */ or // form are stripped early and never reach the compiler.

The preprocessor: the first pass over the text

Before the compiler proper sees anything, the C preprocessor runs over the file and rewrites it as pure text. It performs three main jobs. It expands every #include by literally pasting the named header’s contents in place, so #include <stdio.h> injects the declaration of printf and hundreds of other symbols. It expands #define macros, replacing each use of a macro name with its replacement text; GREETING above becomes the string literal. And it evaluates conditional directives (#ifdef, #if, #else, #endif), keeping or discarding blocks of code, which is how one .c file can compile differently on different platforms. The preprocessor understands nothing about C’s grammar; it only manipulates text and tokens. Its output is a single expanded source ready for the compiler.

The translation unit

The expanded output of the preprocessor for one .c file, with all its included headers spliced in and all macros expanded, is called a translation unit. This is the true atomic input to the compiler: the compiler sees translation units, not files. It is why declarations must be visible in the same translation unit that uses them, and why a header is included rather than merely referenced. It is also why two .c files are compiled independently and only joined later: each is its own translation unit, and neither sees the other’s function bodies during compilation, only the declarations they share through common headers.

Compiling a translation unit into an object file

The compiler takes one translation unit and produces an object file (.o on Unix, .obj on Windows) containing machine code plus a symbol table. Along the way it does the real work of a language: lexing the text into tokens, parsing them into a syntax tree, checking types (does this call match the prototype the header declared?), and generating and optimising machine instructions. Crucially, the compiler does not need the definitions of functions declared elsewhere; a prototype is enough to emit a call and record it as an unresolved symbol. So a .c file that calls printf compiles fine on its own, leaving a note that says “this call needs a function named printf, to be supplied later”.

Linking: resolving symbols and finding main

The linker takes one or more object files plus the libraries they use and joins them into a single executable. Its job is to resolve every unresolved symbol: it matches the call to printf against the definition inside the C standard library, and it matches each call between your own files to the one object file that defines that function. The linker also arranges for program startup code to call main() after the runtime is initialised, which is why main is the entry point. Two classic linker errors follow from this model: an undefined reference means a called function was declared but never defined anywhere in the link, and a duplicate symbol means the same function was defined in two translation units, usually because a definition was placed in a header and included twice.

gcc hello.c -o hello       # preprocess + compile + link in one command
./hello                    # run the resulting native executable

A single command like gcc hello.c -o hello hides all four stages: it preprocesses, compiles and links, then writes one executable. For larger programs a build system such as Make or CMake compiles each .c to its own object file and links them together, recompiling only the files that changed.

Headers and multi-file programs

Real programs span many .c files, and they coordinate through header files. A header holds the declarations (prototypes, types, macros) that multiple source files share; each .c file #includes the headers it needs and defines its own functions. This is the declaration-versus-definition split: the header announces an interface, and exactly one .c file provides each definition. The linker then ties every call to that single definition. Splitting a program this way lets each file compile independently and in parallel, and lets a library ship its headers so your code can call its functions without ever seeing its source.

Turning a .c into an .exe is compilation, not conversion

A common request is to “convert” a .c file to an .exe. There is no file-format conversion involved: the executable is the output of compiling the source, generated fresh by the toolchain. On Windows, gcc program.c -o program.exe with MinGW, or a Build in Visual Studio, produces the native binary; on macOS and Linux, gcc program.c -o program or clang program.c -o program produces a binary with no extension. Similarly, renaming a .c to .txt changes nothing but the label, since the file is already plain text, and renaming a .c to .cpp is a language port rather than a conversion: most C compiles as C++, but C++ is stricter about implicit casts and reserves extra keywords, so expect to fix some errors. The object file the compiler emits along the way is documented separately under OBJ.

Frequently asked questions

How do I compile and run a .c file?

Install a C compiler and run it on the file. On Windows: gcc hello.c -o hello.exe with MinGW, then run hello.exe, or add the file to a Visual Studio project and press Build. On macOS or Linux: gcc hello.c -o hello && ./hello, using the Clang or GCC that ships with the system tools.

Is a .c file C or C++?

.c normally means C source; C++ uses .cpp, .cc or .cxx. Some old Unix code used .c for C++ as well, with an uppercase .C on case-sensitive file systems, which is why the extension is sometimes labelled “C/C++”. Compilers pick the language mode from the extension, and C and C++ differ enough that the distinction matters.

What is the difference between a .c and a .h file?

A .c file contains the actual code, the function definitions. A .h header file contains declarations, the prototypes, types and macros that source files share through #include. You compile .c files; headers are pulled into them by the preprocessor and are not compiled on their own.

References