6 ms·
A variant of this is to mandate that every header #define a documented symbol, and then have a #ifndef guard for this around the inclusion of the header.
by rlkf 6y ago
A variant of this is to mandate that every header #define a documented symbol, and then have a #ifndef guard for this around the inclusion of the header.
- nitrogen 6y agoThe standard practice of putting the ifndef guard inside each header is specifically optimized by compilers, though I don't recall where I read that.
- jstimpfle 6y agoI don't know why this is downvoted. This is exactly how it is. The first time the compiler reads the include file, it remembers where the corresponding #endif is for each #if. The next time the file is included, the compiler can skip over the whole included file. There is no performance advantage from outsourcing the conditional to every including location. Putting an ifndef guard at the location where the file located is not workable. It's terrible boilerplate. To the relatively simple '#include <A.h>' another variable that must be synchronized with dependencies gets added. Plus 2-3 lines for the conditional. At each including location.
- cesarb 6y agoIIRC, this is documented in the CPP part of the GCC manual. Whenever a header file is completely enclosed in a ifndef guard, and that guard is still defined, it will skip the whole file. Another option is "#pragma once"; it's non-standard, but every popular C compiler (even MSVC) understands it, and has the advantage that there's no risk of accidentally using the same include guard for more than one header file.
- pjmlp 6y agoWindows compilers were the first to have it, naturally MSVC understands it.
- ncmncm 6y agoAll production compilers now support `#pragma once`, so the traditional `#include` guard is almost totally obsolete. The only plausible exceptions are in proprietary compilers for microcontroller SDKs.
- simias 6y agoI very rarely encounter #pragma once in the wild personally, and I still always use old school #ifndef guards myself. I can't really see a reason to change: it's not a huge amount of typing, it works everywhere, it's very explicit and not magical. For instance out of the top of my head I don't remember how #pragma once decides what constitutes the same include file. If you have symbolic links, or absolute and relative paths for instance, how does it work? I'm sure I can find the answer in the compiler's documentation, but with #ifndef I don't even have to, it's obvious what's going to happen. I would personally argue that old school guards should be preferred because of this and the fact that they're standard, but I don't feel super strongly about it.
- WJW 6y agoWouldn't it be as simple as maintaining a bloom filter containing the absolute paths of every included file encountered so far? Whenever you encounter #pragma once you check if the file is already present in the bloom filter and return early if it is. If it's a new file you add the file name to the bloom filter and continue processing. It probably even more memory efficient (albeit insignificant in the grand scheme of compiler memory usage) for the compiler to just maintain the bloom filter and not have to deal with hundreds of otherwise unused preprocessor symbols, one per include file.
- branko_d 6y agoBloom filter can have false positives.
- somebodynew 6y agoThe typical argument against pragma once is that it's unclear what should happen if two different hard link paths are used to include a file with the same inode (along with similar situations on Windows or with files on network drives). That is to say, in general, there is no consistent and portable "true" absolute path that uniquely identifies file(s) as conceptually having the same underlying storage. In practice, I have never actually seen a problem arise. The most likely real trigger would probably be a mix of including a library through a path that indicates a specific version and including it through a path that uses a "latest stable" link. That is already fragile and asking for trouble, though.