2

In a very simplistic way, I understand:

"Compilation" = "Pre-processing" + "Parsing" + "Linking" + "Executable"

All the macros and other such pre-processing directives are taken care at the "Pre-processing" stage itself.

Suppose, if we have several macros in source code, then will they cause any significant time in pre-processing stage?

To clarify, I am talking about the macros which are #defined in header file but are not #undefed in that same file for some or no reason.
Due to its practicality, it will be helpful if anyone has any profiling info on this topic.

6
  • I doubt there's any general answer to this, and in practice this probably only matters if it's in a header file included by a few hundred other files. But are you comparing macros versus nothing or macros versus real functions?
    – Ixrec
    Apr 15, 2016 at 7:13
  • @Ixrec, in a way I am comparing "more macros" with "less macros". For example, imagine in "main.h", I #define 100 macros. Now those macros are not #undefd. This file is included by all the other source files. Now this means, that each macro word has to be searched in whole source code for replacement. This can be efficient, but at least 100 such searches have to happen. Suppose, I could manage to reduce these 100 to 50, then this searches may become half. What I want to know that, does it cause any significant save in preprocessing time or just marginal?
    – iammilind
    Apr 15, 2016 at 7:19
  • 1
    That's not how macro replacement works. Instead, as the lexer parses tokens, it looks up the names in the macro table. The table is typically a hash table, so unless the compiler uses a poorly structured table the lookup will be O(1), i.e. roughly the same time whether you use 10 macros or 1000. Apr 15, 2016 at 7:41
  • If you really want to measure the effect of macro definitions on the efficiency preprocessing, just run your compilation with the flag that signals "perform only preprocessing" (for GCC I think this is -E) and compare different versions. Apr 15, 2016 at 7:55
  • 3
    Those are really the most boring, and least time-consuming things a compiler does. The most interesting, and most time- (and memory-)consuming things are semantic analysis (equivalent to solving the Halting Problem in the general case), type-checking (ditto), type-inference (ditto), and optimization (ditto, and even the heuristic algorithms are often NP-complete or at least exponential). You are also missing code generation, which is kind-of the most important step (after all, that's why you compile, isn't it?) but also not terribly slow, except for register-allocation (which is NP-complete). Apr 15, 2016 at 8:48

1 Answer 1

6

Today, the preprocessing is actually happening inside the compiler (e.g. inside the cc1plus executable started by g++ command). Use g++ -C -E to get the preprocessed form.

Preprocessing and parsing is a well known art, and does not take that much time. However, the standard headers of C++11 (e.g. <vector> or <map>) are pushing a lot of stuff. For example, #include <vector> is pushing about ten thousand lines of code on GCC/Linux with GCC 5. This is one of the reasons why compiling C++ code is slow (another reason is that C++ being incredibly context sensitive, parsing it is slow: overloaded functions, naming ambiguity, etc...).

Having many thousands of almost unused #define-d macros is not an issue today. (perhaps having millions of #define might be an issue; I leave you to try that) Look into the source code of GTK or of the Linux kernel for some example.

The reason it is not a real issue today (on current laptops & desktops, with e.g. 8GBytes of RAM) is that it is mostly filling some symbol table, and these tables can routinely handle many hundred thousands symbols.

Notice that optimizing compilers take lots of time in optimization. And C++ code practically needs to be optimized (in particular, because it has lots of trivial inlinable member functions, notably in template instantiation for standard containers, etc...). Even C code needs to be optimized (because current superscalar out-of-order multicore pipelined processors are really different from the processors of the previous century for which C have been designed).

If you are curious about where the GCC compiler is spending its CPU time (see also this question) pass -freport-time to g++ (and also -Wall -O2 for example). If you are even more curious, customize your GCC compiler with MELT (but that requires understanding something about GCC internals, which takes weeks).

Notice that C (not C++) compilation is "fast" for its preprocessing & parsing phases (the bulk of the CPU time happens in optimization passes; experimentally, with gcc -O2, the compilation time is proportional to the square of the "size" of the largest compiled function). If you don't care about optimized code you could even try the tinycc compiler (which compiles about ten times faster than GCC or Clang, but produces slow machine code).

1
  • 1
    +1. Pretty much everything a compiler does except the stages the OP listed is slow, with "slow" == "either NP-complete or solving the Halting Problem". Apr 15, 2016 at 8:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.