This paper shows that CPP, the preprocessor of the C language, can be seen as a programming language in which directives are statements, parametrized macros are functions, files are procedures, directories are modules, and command lines are programs. The semantics of CPP can therefore be described using traditional techniques. This paper describes the semantics of CPP in a denotational style. By contrast with previous work, the full semantics is taken into account including non trivial aspects such as recursive macros, stringification and concatenation.