3 ms·
>How can _any_ language compile a unit passing a struct Foo on the stack without knowing the size of Foo. The idea is not to compile a unit without knowing the
by john_moscow 6y ago
>How can _any_ language compile a unit passing a struct Foo on the stack without knowing the size of Foo.
The idea is not to compile a unit without knowing the size of Foo. It's about making sure you figure out sizeof(Foo) in near constant time.
With C#/Pascal, it means:
* For each referenced module load its symbol table into RAM. If implemented cleverly, this is literally one read() call.
* For each referenced symbol, search each hash table until you find it. Since the hash tables are only built during compilation, you can auto-size them so that an average lookup takes just 1-2 steps.
* Bonus point: for libraries, you can merge the hash tables. So n is now a number of libraries, not number of files.
With C++ you are stuck reparsing megabytes of code at the beginning of each translation unit. It's millions of times slower than reading a couple of pages from disk to RAM.
- jstimpfle 6y ago> For each referenced module load its symbol table into RAM. If implemented cleverly, this is literally one read() call. That might easily be a lot slower than building a huge hash table at the start. But there is a huge advantage to be had if the effort of building the large hash table can be shared between all files that are simultaneously built.
- Galanwe 6y agoI feel stupid but I still don't understand what would prevent a C++ compiler to do exactly what you just described. The preprocessor does not have side effects. That means whenever a header is compiled, you could store a hash of all used defines and their checksum. Whenever that file should be read again, compare the checksum of the used defines to the one stored. If they are the same, you can reuse the precompiled header. If not, create a new version of the precompiled header for a different set of defines. 99.9% of the time, every single header is included with the exact same set of defines.
- candiodari 6y agoOk. This is what prevents a C/C++ compiler from doing that: config.h #define I_LIKE_FEATURE_X b.h #include "config.h" struct App { #ifdef I_LIKE_FEATURE_X FeatureXImplementation *fx; #endif } The preprocessor can change the size of structs (even redeclare them several times, or create new ones with unique names or ...)
- Galanwe 6y agoThat was already accounted in my answer > whenever a header is compiled, you could store a hash of all used defines and their checksum. Whenever that file should be read again, compare the checksum of the used defines to the one stored. If they are the same, you can reuse the precompiled header. If not, create a new version of the precompiled header for a different set of defines. In this example, when compiling b.h, you can store that this compiled header is for when state<I_LIKE_FEATURE_X=1>. Next time you have to include it, check if the state matches. If that is the case, use the precompiled header. If not, create a new version for state<I_LIKE_FEATURE_X=0>. As also already mentioned, it is quite rare for a single project to include the same file with a different configuration of defines that would change it. 99.9% of the times you would just -DI_LIKE_FEATURE_X project wide, so à single precompiled header only would be necessary
- bleepblorp 6y agoI don't see why this is a problem for reusing precompiled headers in the way the parent post suggested. If the compiler records the value of every #define when it precompiles b.h, if b.h is #included again with the same #defines set, the compiler can reuse the same precompiled version of b.h. Indeed, if the compiler-buildsystem detects that b.h has been #included with a different set of #defines, it might be a good idea to issue a warning because that could be an indication that the codebase is about to footgun itself.