Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C-Preprocessor: check for included file

7 views
Skip to first unread message

Thomas Schafbauer

unread,
May 28, 1997, 3:00:00 AM5/28/97
to

I am trying to avoid unnecessary, duplicate inclusion of header-files.
This can be done via a

#if !defined(__STDLIB_H) && !defined(_INC_STDLIB) &&
!defined(_STDLIB_INCLUDED)
.....
#endif

However, there is no platform independent name to signal, if a file is
already
included, so I tried

#define INCLUDED(a) (defined(__ ## a ## _H) || defined(_ ## a ##
_INCLUDED))

and check via

#if !INCLUDED(stdlib)
# include <stdlib.h>
#endif

One could easily adjust this for each system.
However, this works does not work with all compilers, also lint fails.

lint
"machine.h", line 165: unexpected "("
"machine.h", line 171: unexpected "("


Thanks
Thomas

Jens Schweikhardt

unread,
May 29, 1997, 3:00:00 AM5/29/97
to

In article <5milt3$d...@solutions.solon.com> Thomas Schafbauer <Thomas.S...@mchp.siemens.de> writes:
# I am trying to avoid unnecessary, duplicate inclusion of header-files.

There is no portable way.

# This can be done via a
#
# #if !defined(__STDLIB_H) && !defined(_INC_STDLIB) &&
# !defined(_STDLIB_INCLUDED)
# .....
# #endif
#
# However, there is no platform independent name to signal, if a file is
# already
# included,

Exactly.

# so I tried
#
# #define INCLUDED(a) (defined(__ ## a ## _H) || defined(_ ## a ##
# _INCLUDED))
#
# and check via
#
# #if !INCLUDED(stdlib)
# # include <stdlib.h>
# #endif
#
# One could easily adjust this for each system.

Yuck! :-)

# However, this works does not work with all compilers, also lint fails.

Don't do that then.

Why are you so concerned about multiple inclusion? Is it a
performance problem? Remember, all ISO C headers are idempotent, i.e.
they can be included multiple times, always having the same effect.
(Language lawyer bonus point: where can the effect differ?).

All you can do is make sure your *own* headers aren't included more
than once. The best strategy is to get your #include nesting
straight. There's *always* a way to organize your headers in a way so
that no header is ever included twice or more. Even without the use
of additional macros. If this seems impossible then probably a
redesign of your sources is in order, IMHO.

# Thanks
# Thomas

Regards,

Jens
--
Jens Schweikhardt http://www.uni-stuttgart.de/People/schweikhardt/home.html
SIGSIG -- signature too long (core dumped)

k...@nt.com

unread,
May 29, 1997, 3:00:00 AM5/29/97
to

In article <5milt3$d...@solutions.solon.com>,

Thomas Schafbauer <Thomas.S...@mchp.siemens.de> wrote:
>I am trying to avoid unnecessary, duplicate inclusion of header-files.
>This can be done via a
>
>#if !defined(__STDLIB_H) && !defined(_INC_STDLIB) &&
>!defined(_STDLIB_INCLUDED)
>.....
>#endif

This is not necessary. Conforming C implementations must ensure that the
standard header files can be included in any order, and can be included
multiple times without adverse effects.

Most vendors accomplish this by implementing standard headers as ordinary
files, and by using the above simple preprocessor trick.

>However, there is no platform independent name to signal, if a file is

>already
>included, so I tried
>

>#define INCLUDED(a) (defined(__ ## a ## _H) || defined(_ ## a ##

>_INCLUDED))
>
>and check via
>
>#if !INCLUDED(stdlib)
># include <stdlib.h>
>#endif

You are doing redundant work. Have a look at how your system implements
stdlib.h. For example, if you are in UNIX, look at the file
/usr/include/stdlib.h. You may be pleasantly surprised.

>One could easily adjust this for each system.

>However, this works does not work with all compilers, also lint fails.

That's because once macro expansion kicks in, the expanded results are no
longer re-interpreted as a preprocessor directive. That is, when a macro
produces a token that looks like a preprocessor keyword, it is not treated
as a preprocessor keyword. You can't do stuff like:

#define INC include
#INC <stdio.h>

Herve Couppe de Lahongrais - CDL

unread,
May 29, 1997, 3:00:00 AM5/29/97
to

Thomas Schafbauer wrote:
>
> I am trying to avoid unnecessary, duplicate inclusion of header-files.
> This can be done via a
>
> #if !defined(__STDLIB_H) && !defined(_INC_STDLIB) &&
> !defined(_STDLIB_INCLUDED)
> .....
> #endif

Why are you worrying about that ? Standard header files are idempotent
i.e. you can include them as often as you want. For example, the
begining of <stdio.h> might look something like that :

#ifndef _STDIO_INCLUDED
#define _STDIO_INCLUDED

to prevent multiple inclusions of the same header file.

[ snip ]

--
Herve Couppe de Lahongrais (SEU) | Eurocontrol Experimental Centre
mailto:c...@eurocontrol.fr | France

Herve Couppe de Lahongrais - CDL

unread,
May 29, 1997, 3:00:00 AM5/29/97
to

Eric Amick

unread,
Jun 1, 1997, 3:00:00 AM6/1/97
to

Jens Schweikhardt (schw...@rubin.noc.dfn.de) wrote:
> Why are you so concerned about multiple inclusion? Is it a
> performance problem? Remember, all ISO C headers are idempotent, i.e.
> they can be included multiple times, always having the same effect.
> (Language lawyer bonus point: where can the effect differ?).

All headers but one; <assert.h> depends on whether NDEBUG (which is not
defined in <assert.h>) is defined, so it can't be idempotent.

--
Eric Amick
Columbia, MD
eam...@clark.net

Christian Bau

unread,
Jun 1, 1997, 3:00:00 AM6/1/97
to

In article <5ml7em$n...@solutions.solon.com>, Herve Couppe de Lahongrais -
CDL <herve.couppe-...@eurocontrol.fr> wrote:

> Thomas Schafbauer wrote:
> >
> > I am trying to avoid unnecessary, duplicate inclusion of header-files.
> > This can be done via a
> >
> > #if !defined(__STDLIB_H) && !defined(_INC_STDLIB) &&
> > !defined(_STDLIB_INCLUDED)
> > .....
> > #endif
>
> Why are you worrying about that ? Standard header files are idempotent
> i.e. you can include them as often as you want. For example, the
> begining of <stdio.h> might look something like that :
>
> #ifndef _STDIO_INCLUDED
> #define _STDIO_INCLUDED
>
> to prevent multiple inclusions of the same header file.

stdio.h is a standard header file, so the C standard defines that you can write

#include <stdio.h>

as often as you like, with no change to the meaning of your program.
However, on many compilers including a file takes considerable compile
time. I am quite sure that is the answer to "Why are you worrying about
it". The technique you described does _not_ prevent multiple inclusion
itself, it only prevents that multiple inclusion keeps your program from
working.

Of course this technique (#ifndef, #define etc...) is very useful. I
think it would be relatively easy for a compiler to take advantage of this
and reduce compile time without any change to the including program in the
following way:

Whenever the compiler includes a file, it should check whether that
file has the form

#ifndef <identifier1>
#ifndef <identifier2 etc...>
<more lines without a #endif matching these #ifndefs>
#endif /* identifier2 */
#endif /* identifier1 */

and remember the file name and the identifiers. Then if an include for the
same file is encountered again, the compiler just has to check if any of
the identifiers is defined, and if so, there is no need to include the
file again.

BTW. Years ago when I was using a really slow compiler, my headers started like

#ifdef __MYHEADER__
#error "myheader.h" included twice
#endf
#define __MYHEADER__

This got definitely rid of all unnecessary includes, reducing compile time.

-- For email responses, please remove the last emm from my address.
-- For spams, please send them to whereever...@but.not.here

Martin Sohnius x24031

unread,
Jun 1, 1997, 3:00:00 AM6/1/97
to

Herve Couppe de Lahongrais - CDL (herve.couppe-...@eurocontrol.fr) wrote:
: Thomas Schafbauer wrote:
: >
: > I am trying to avoid unnecessary, duplicate inclusion of header-files.
: > This can be done via a
: >
: > #if !defined(__STDLIB_H) && !defined(_INC_STDLIB) &&
: > !defined(_STDLIB_INCLUDED)
: > .....
: > #endif

: Why are you worrying about that ? Standard header files are idempotent
: i.e. you can include them as often as you want. For example, the
: begining of <stdio.h> might look something like that :

: #ifndef _STDIO_INCLUDED
: #define _STDIO_INCLUDED

: to prevent multiple inclusions of the same header file.

: [ snip ]

In fact, on mine it looks like this:

$ cat /usr/include/stdio.h
/* Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996 Novell, Inc. All Rights Reserved. */
/* Copyright (c) 1988, 1990 Novell, Inc. All Rights Reserved. */
/* All Rights Reserved */

/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF Novell Inc. */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */

#ifndef _STDIO_H
#define _STDIO_H
#ident "@(#)/usr/include/stdio.h.sl 1.1 u211 09/27/96 52255 SCO"

[..well, heck, no, I am *not* publishing the bloody code..]

#endif /*_STDIO_H*/


Do the same for own headers, just don't choose something matching
_[A-Z_].* (or any other reserved name) as the name of the macro.

--
*******************************************************************
Martin F. Sohnius msoh...@novell.co.uk
Novell IS & T, Bracknell, England +44-1344-724031
*******************************************************************
* if (status = UNDER_NUCLEAR_ATTACK) *
* launch_full_counterstrike(); *
*******************************************************************
(C) 1997 M.F.Sohnius -- free distribution on USENET
(Not a spokesperson -- just a cyclist!)

Thomas Schafbauer

unread,
Jun 3, 1997, 3:00:00 AM6/3/97
to

Herve Couppe de Lahongrais - CDL wrote:

> > I am trying to avoid unnecessary, duplicate inclusion of header-files.
> > This can be done via a
> >
> > #if !defined(__STDLIB_H) && !defined(_INC_STDLIB) &&
> > !defined(_STDLIB_INCLUDED)
> > .....
> > #endif
>
> Why are you worrying about that ? Standard header files are idempotent
> i.e. you can include them as often as you want. For example, the
> begining of <stdio.h> might look something like that :
>
> #ifndef _STDIO_INCLUDED
> #define _STDIO_INCLUDED
>
> to prevent multiple inclusions of the same header file.


It's a way of reducing compilation time.
I check for __STDLIB_H _STDLIB_H _INC_STDLIB _STDLIB_INCLUDED
which works for many systems I know.

Is recursive macro expansion in precompiler statements
part of standard ANSI-C?

#define IS_DEFINED(a) defined(a)
#if IS_DEFINED(LOCAL_HONCHO)

Thanks for your help
Thomas

k...@nt.com

unread,
Jun 5, 1997, 3:00:00 AM6/5/97
to

In article <5n2lch$6...@solutions.solon.com>,
Thomas Schafbauer <schaf...@aol.com> wrote:

>Is recursive macro expansion in precompiler statements
>part of standard ANSI-C?

No. Get the standard and then you can read for yourself!

>#define IS_DEFINED(a) defined(a)
>#if IS_DEFINED(LOCAL_HONCHO)

That is wrong. The directive has to make sense before any macro substitution is
performed. Furthermore, the results of macro substitution can never be
interpreted as a preprocessor directive, even if they expand to a line that
begins with #.

The only recursive aspect of macro expansion is that the results of macro
expansion are repeatedly re-examined for the occurence of more macros. Once a
macro name has been expanded, it is ``remembered'' by the preprocessor so that
it will not again be expanded should its identifier reappear during expansion.

Lawrence Kirby

unread,
Jun 5, 1997, 3:00:00 AM6/5/97
to

In article <5n2lch$6...@solutions.solon.com>
schaf...@aol.com "Thomas Schafbauer" writes:

>Herve Couppe de Lahongrais - CDL wrote:
>
>> > I am trying to avoid unnecessary, duplicate inclusion of header-files.
>> > This can be done via a
>> >
>> > #if !defined(__STDLIB_H) && !defined(_INC_STDLIB) &&
>> > !defined(_STDLIB_INCLUDED)
>> > .....
>> > #endif
>>
>> Why are you worrying about that ? Standard header files are idempotent
>> i.e. you can include them as often as you want. For example, the
>> begining of <stdio.h> might look something like that :
>>
>> #ifndef _STDIO_INCLUDED
>> #define _STDIO_INCLUDED
>>
>> to prevent multiple inclusions of the same header file.
>
>
>It's a way of reducing compilation time.
>I check for __STDLIB_H _STDLIB_H _INC_STDLIB _STDLIB_INCLUDED
>which works for many systems I know.

However since standard headers are protected as above this won't make that
much difference overall unless the headers are very long (maybe an
implementation supplied header like windows.h, but not the standard C
header). Also compilers like gcc are clever enough to optimise this
anyway. You're better off writing clear code.

>Is recursive macro expansion in precompiler statements
>part of standard ANSI-C?
>

>#define IS_DEFINED(a) defined(a)
>#if IS_DEFINED(LOCAL_HONCHO)

No. The standard says 6.8.1:

"If the token defined is generated as a result of this replacement
process or ... the behaviour is undefined"

--
-----------------------------------------
Lawrence Kirby | fr...@genesis.demon.co.uk
Wilts, England | 7073...@compuserve.com
-----------------------------------------

0 new messages