4 ms·
> There are reasons why actual C/C++ compilers don't do this. http://gcc.gnu.org/onlinedocs/cpp/Once-Only-Headers.html#Once-Only-Headers http://gcc.gnu.org/onl
by clarry 12y ago
> There are reasons why actual C/C++ compilers don't do this.
http://gcc.gnu.org/onlinedocs/cpp/Once-Only-Headers.html#Once-Only-Headers http://gcc.gnu.org/onlinedocs/cpp/Once-Only-Headers.html#Onc...
This construct is commonly known as a wrapper #ifndef. When the header is included again, the conditional will be false, because FILE_FOO_SEEN is defined. The preprocessor will skip over the entire contents of the file, and the compiler will not see it twice.
CPP optimizes even further. It remembers when a header file has a wrapper ‘#ifndef’. If a subsequent ‘#include’ specifies that header, and the macro in the ‘#ifndef’ is still defined, it does not bother to rescan the file at all.
- pjmlp 12y agoWhich breaks #includes written to be included multiple times and provide different outcomes based on defined macros. C based toolchains are just broken.
- clarry 12y agoIf a file is intended to be read multiple times with different results, then obviously you don't want to prevent it being read twice. However, we were talking about preventing the hit from reading a file twice unnecessarily. The quoted text says it doesn't bother rescanning if the macro is still defined. How do you get a different outcome from scanning the same file with the same define? Can you provide an example where this breaks things?
- ambrop7 12y agoYes, it's an optimization, it'll just make the common case (include guard) faster, without breaking anything.
- pjmlp 12y agoHow do you force the file to be re-read multiple times when the outcome is not idempotent?
- clarry 12y agoI do not understand why you are arguing about this. There are two scenarios: in one you want to prevent a file from being read multiple times because it wastes resources (and in some sad cases, might cause issues with redefinition). In this case, you use the include guards and the compiler can do a trick to optimize out unneeded scanning. You have this other hypothetical scenario in which you purposefully want a file to be read multiple times, with a different outcome (this kind of trickery isn't usually possible at all in other languages with module system so it is funny to argue about C being broken). Now I don't think this is a common scenario or even a good one to be in, but it is possible. The solution is simple: don't try to prevent the file from being read multiple times. Why would you try to prevent it, if it is meant to be read multiple times? You are arguing that a door is broken because you cannot walk in through it if you close the door. Don't close the door if you want to walk in...
- pjmlp 12y agoBecause it is an optimization that relies on well behaved developers and we all know how good such assumptions end, specially in big teams with high attrition.
- dllthomas 12y agoAs I read this, if the compiler determines that (with the #define set) the file is effectively empty, it knows it can just check the #define next time rather than re-reading. Without this optimization, you get the same result slower. It doesn't depend on well-behaved anything to get a result just as correct as without the optimization. With the single possible exception of a file that changes on disk between the multiple includes in the same build step. That is not a situation I have ever encountered and I am not at all sure it is supported and there aren't a bazillion other things that would break it in any given compiler chain (certainly at least line directives would be wrong, but that's arguably minor I guess).
- Peaker 12y agoIt doesn't rely on anything. It's a correct optimization that does not change any behavior at all. It only speeds things up.
- pjmlp 12y agoI am not talking about include guards, rather macros that affect the outcome of specific file. It is not a very clean way of coding, but there are many enterprise developers that provide files without include guards and include them multiple times. An example would be generic data structures in C done with macros. #define DATA_TYPE int #define DATA_NAME intList_t #include <list.h> typedef struct { /* ... */ } Node; #define DATA_TYPE Node #define DATA_NAME nodeList_t #include <list.h>
- stormbrew 12y agoIt's pretty unlikely that list.h would have a trivial include guard, so I don't see how the above optimization would break it. An include guard in list.h would prevent you from using it properly with or without the optimization.
- pjmlp 12y agoNot when you #undef it. That was just a possible example.
- dllthomas 12y agoIf list.h has no include guard, it gets included with or without this optimization. If it has an include guard and you #undef it, then it gets included again with or without this optimization. If you it has an include guard and you do not #undef it, it does not get included again, with or without this optimization. In no case does this optimization change the code emitted.
- deleted 12y ago[deleted]
- krig 12y agoNote that this only partially helps with a subset of the problem (and modules as proposed don't fix the issue, they just help a bit more): CPP still needs to make separate passes for each translation unit, for example. I'd recommend reading the link I put in my original post...