Path: utzoo!utgpu!watmath!clyde!att!pacbell!ames!haven!adm!smoke!gwyn From: gwyn@smoke.BRL.MIL (Doug Gwyn ) Newsgroups: comp.lang.c Subject: Re: C Style Message-ID: <9336@smoke.BRL.MIL> Date: 11 Jan 89 08:48:50 GMT References: <2688@ficc.uu.net> Reply-To: gwyn@brl.arpa (Doug Gwyn (VLD/VMB) ) Organization: Ballistic Research Lab (BRL), APG, MD. Lines: 65 In article <2688@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes: >I have been told that the following mechanism for handling nested includes >is unreliable and/or unportable, but for the life of me I can't see how: >graphics.h: > #ifndef GRAPHICS_H > #define GRAPHICS_H > ... > #endif >windows.h: > ... > #ifndef GRAPHICS_H > #include GRAPHICS_H > #endif > ... >menus.h: > ... > #ifndef GRAPHICS_H > #include GRAPHICS_H > #endif > ... >Now this allows a programmer to include windows.h and menus.h, without >having to (a) know they need to include graphics.h, and (b) worry about >graphics.h being included twice. >What's wrong with this picture? The only thing wrong is your syntax. You mean #include "graphics.h" in the latter two files. In fact there is no need to place conditionals around those inclusions, since the included file will have no effect if it is already in force, bacause it checks its one-time lockout flag and avoids redefining things after the first time it's included in a translation unit. Notes: 1. GRAPHICS_H needs to be reserved for this use. If this header is part of an application (as indicated), then you just have to keep track of such symbols, perhaps by making the rule that the _H suffix is reserved for them. If you were implementing standard headers for a C implementation, you would need to use a lockout symbol that's in the implementation's reserved name space, e.g. __CTYPE_H. 2. If the header just defines macros and structures, and declares types of external objects and functions, then you don't need to ensure one-time actions, because such actions can be repeated safely. Typedefs are the main things that need to be protected against a second invocation. 3. Notwithstanding point 2, if the header includes others then it should probably use lock-out symbols, to avoid infinite recursion if the other headers include THIS one. 4. Application headers should NOT include standard headers, because many C implementations do not provide idempotent standard headers, so bookkeeping becomes a real mess unless you adopt the simple rule that all application headers are idempotent and never include system headers inside themselves. (ANSI C requires the standard headers to be idempotent, i.e. includable multiple times with the same effect as a single inclusion.) 5. Include headers before doing anything else in the source. 6. We use this scheme in a major project and it works fine.