5 ms·
I would strongly recommend that people new to C and reading this comment do not follow this advice. It might have made sense back when it was written but it's n
by simias 6y ago
I would strongly recommend that people new to C and reading this comment do not follow this advice. It might have made sense back when it was written but it's not how modern C is typically written, and it would be very annoying for modern C coders to put up with these shenanigans.
Multiple inclusions are hardly a problem nowadays, with header guards it means that subsequent inclusions won't actually include anything and the performance impact is fairly negligible the vast majority of the time. C compilers are pretty damn fast these days and in my experience it's the optimization pass that slows things down the most, not parsing includes.
Also in general I tend to take what Rob Pike says with a grain of salt, he's a very smart guy and he definitely says interesting things but he has weird idiosyncracies. He's definitely worth listening to, but I wouldn't follow his advice blindly. See his weird take about how "syntax highlighting is juvenile" for instance.
- pdw 6y agoMost modern C compilers are aware of include guards: if they notice that the _entire_ file is enclosed in include guards, they won't read it a second time.
- pjmlp 6y agoThat breaks undefs before includes.
- pdw 6y agoWell yeah. If you make normal, idiomatic use of include guards, compilers will be able to apply this optimization. If you do weird stuff, they'll be forced to re-read the file. https://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html https://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.htm...
- guenthert 6y agoI haven't opened up my C compiler to verify this, but even for ancient compilers that would be a non-issue, as they see only what the preprocessor hands them. Re-reading (i.e. parsing by the preprocessor) an include file isn't so bad either, as it is already cached. I find this focus on compilation speed curious. At my last workplace a full built took a good share of the day (!) and was typically done overnight. Building during the daytime was discouraged, as it happened on our workstations, slowing down everything else. We found ways to cope, chiefly learning which subsets are autarkic, i.e. finding the least general Makefile which when invoked would catch your recent changes and wouldn't traverse too much of the tree. Not ideal, but workable.
- algo_trader 6y ago> full built took a good share of the day Yikes Was this with/out some sort of cluster support? Which language? Is this due to legacy practices, or is it simply a difficult build? I am asking because i am involved with a parallel build project. and often there is plenty low hanging fruits
- guenthert 6y ago> Yikes Was this with/out some sort of cluster support? Each developer built on their own workstation. We meant to look into built-cluster, but we never got around to it. > Which language? C++ mostly old style, some C++11, quite a bit of template programming (but I haven't seen anything too fancy). > Is this due to legacy practices, or is it simply a difficult build? It sure was an old code base, not sure what you mean by legacy practices (but that might make it a yes ;-} Not sure either, what would make it difficult, but there were C++ templates and it was fairly large (sum of resulting object files in the order of a few hundred MiB).
- flohofwoe 6y agoHeaders not including headers is still good advice, it's not so much about fast compiles (at first at least while a project is small), but about not letting header inclusions grow out of control (see almost every C++ project with more than a few hundred source files, it's almost impossible to clean up unused headers, and even when that happens - after a few weeks it's back to the old mess). See here for a relatively recent take on this: https://ourmachinery.com/post/physical-design/ https://ourmachinery.com/post/physical-design/
- simias 6y agoThe only practical issue with "out of control" includes is still compilation time though, especially if modifying a single file causes many other files to rebuild because they include it directly or indirectly. Beyond that I really don't care about it, I don't usually bother to micromanage my #includes, I don't really see the point. Beyond that I think that very complicated include graphs are usually a sign that there's an architectural problem with the application, forbidding includes within includes treats the symptom, not really the core of the issue. As a quick example of some code I wrote not long ago: I have a microcontroller communicating with an external chip over a serial link using a custom protocol. I have a "serial.h" file that describes the API to send and receive serial messages, then a "protocol.h" that implements the higher level protocol. protocol.h includes serial.h since it uses it as a lower layer, it's effectively a dependency. I don't really think it's a problem. So I'm not really sure that it makes a lot of sense to forbid includes within includes as a rule of thumb. I guess if I was to make a rule it would be "include trees are fine, include graphs are bad"? As in, there shouldn't be cycles in the include graph?
- ghshephard 6y agoYeah - so layer-lawyer would argue that the only thing that needs to talk to serial.h would be the protocol - but, in the real world of deployments that actually work in the field, it's often the case that layer lawyers get in the the way, and being able to bypass the protocol to talk directly to the phy is a thing - which means you end up including the phy at multiple places. Purity vs Practicality.
- deleted 6y ago[deleted]
- butterisgood 6y agoHeaders not including other headers is a great thing IMO. If you’re coming into a code base with new eyes there’s less confusion as to where things came from. Of course if you’re reading code - ctags, and cscope are invaluable. I’ve yet to use this fancy new LSP stuff but it seems popular. Convenience headers can be ok occasionally but it kind of runs in the face of writing modular software at times. Syntax highlighting has caught a few mistakes for me in the past but I do think it’s kind of a crutch.
- Cyph0n 6y agoNot including headers in header files can be confusing. Say you maintain a library (lib1.h) that exports an API that takes in an argument defined in lib2.h. If you do not include lib2.h in lib1.h, then the users of your API need to include lib2.h before lib1.h in every source file and header. With a larger number of dependencies, this can become unwieldy for users. In addition, future maintainers of your library may also find it confusing why things break when includes are reordered.