I consider them to serve different purposes. For stuff like the Linux Kernel, the preprocessor is great because it can be used with any number of different types of files the Linux Kernel has in it's source. The Kernel configuration basically just becomes a bunch of #define's, and you can access that information from C, assembly, linker scripts, etc...