[comp.lang.c] Include files

raghavan@umn-cs.CS.UMN.EDU (Vijay Raghavan) (01/28/89)

 Is the Sun style of surrounding the text of standard "include" files 
with a #ifndef-#endif pair really okay? Specifically, does the standard
condone/permit/require stdio.h (say) to have the following structure: 

#ifndef FILE 
 ...
#define FILE struct _iobuf
 ...
#endif !__FILE

 If it does, programs like the following should not compile: 

main() {
#include <stdio.h>
FILE *xx;
... 
}

proc1() {
#include <stdio.h>
FILE *yy;
...
}

Vijay Raghavan 

gandalf@csli.STANFORD.EDU (Juergen Wagner) (01/28/89)

Vijay Raghavan (raghavan@umn-cs.cs.umn.edu) writes:
> Is the Sun style of surrounding the text of standard "include" files 

I am not sure that's "Sun" style. It is just a way of preventing a header
file from being included twice because you'll never know who else includes
that particular file.

>with a #ifndef-#endif pair really okay? Specifically, does the standard
>condone/permit/require stdio.h (say) to have the following structure: 

Why should the standard require/forbid such files? There is a rationale for
having them: Header files as found in /usr/include/... are supposed to contain
global definitions and declarations, i.e. items which are typically included
at the beginning of a module (not a function). Having things like stdio local
to a function sounds a little strange, in particular because <stdio.h> on
e.g. Suns says something like
	extern  struct  _iobuf {...}
and a number of #defines, i.e. global declarations and definitions.
Redefinition of these concepts isn't necessary/is treated as an error.

> If it does, programs like the following should not compile: 
>...

Why would one want to use such a program structure as opposed to having a
single inclusion of <stdio.h>? I thought about it but couldn't come up with
an answer.

There certainly are other cases where multiple inclusion is meaningful. Yet,
I would claim that in most of these cases, a single inclusion which defines
an appropriate macro would be sufficient. I can be convinced of the opposite!

-- 
Juergen Wagner		   			gandalf@csli.stanford.edu
						 wagner@arisia.xerox.com

gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/28/89)

In article <10991@umn-cs.CS.UMN.EDU> raghavan@umn-cs.cs.umn.edu (Vijay Raghavan) writes:
- Is the Sun style of surrounding the text of standard "include" files 
-with a #ifndef-#endif pair really okay? Specifically, does the standard
-condone/permit/require stdio.h (say) to have the following structure: 
-#ifndef FILE 
- ...
-#define FILE struct _iobuf
- ...
-#endif !__FILE

Well, more or less.  There are several detailed points involved here.

- If it does, programs like the following should not compile: 
-main() {
-#include <stdio.h>
-FILE *xx;
-... 
-}
-proc1() {
-#include <stdio.h>
-FILE *yy;
-...
-}

The first point is that the standard headers may be included only
outside all function bodies (i.e. at file scope level).

The next point is that a #defined macro's scope extends to the end
of the translation unit, not just to the end of a block.

The third point is that FILE should be a typedef, not a #define.

The final point is that the standard headers may be included more
than once with no effect different from being included exactly once.
This is what the "#ifndef FILE" was attempting to accomplish.

raghavan@umn-cs.CS.UMN.EDU (Vijay Raghavan) (01/29/89)

In article <9526@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
<In article <10991@umn-cs.CS.UMN.EDU> raghavan@umn-cs.cs.umn.edu (I) wrote:
<>[...] does the standard
<>condone/permit/require stdio.h (say) to have the following structure: 
<>#ifndef FILE 
<> ...
<>#define FILE struct _iobuf
<> ...
<>#endif !__FILE
<
<Well, more or less.  There are several detailed points involved here.
<
<> If it does, programs like the following should not compile: 
<>main() {
<>#include <stdio.h>
<>FILE *xx;
<>... 
<>}
<>proc1() {
<>#include <stdio.h>
<>FILE *yy;
<>...
<>}
<
<The first point is that the standard headers may be included only
<outside all function bodies (i.e. at file scope level).

   May? Does this mean the same as "are required to"? (Excuse me, but 
that simple English word "may" has always given me trouble. I think it
is because too many people use it as a synonym for "can").

   My question was simple: Should a program like
the above give compilation errors? I don't necessarily adopt that style
of including the same header file in two different functions in the same
source file; I found it in a Path Pascal compiler I was porting to a Sun
environment. (Actually, the included file was "stat.h" but the point is 
the same). Treat it as a question of academic interest only, if you like.
 
<
<The next point is that a #defined macro's scope extends to the end
<of the translation unit, not just to the end of a block.

I realize this of course. I think you missed the reason why the
program won't compile when the included file has the "#ifndef #endif"
pair surrounding it. It isn't because FILE is
not defined but because struct _iobuf is undefined in proc1().

<
<The third point is that FILE should be a typedef, not a #define.

I'll accept this if you say so (but note that a lot of implementations
seem to think otherwise). However, this makes no difference to the
example I gave. It still won't compile because the lexical scope of the typedef
will still be restricted to the main(){} block.

<
<The final point is that the standard headers may be included more
<than once with no effect different from being included exactly once.
<This is what the "#ifndef FILE" was attempting to accomplish.

I *know* what the "#ifndef FILE" was attempting to accomplish. All I am
saying is that the effect is not the same (as without the "#ifndef") when
the inclusions occur in different mutually non-nesting blocks of the same file.

  Vijay Raghavan

gandalf@csli.STANFORD.EDU (Juergen Wagner) (01/30/89)

In article <10995@umn-cs.CS.UMN.EDU> raghavan@umn-cs.cs.umn.edu (Vijay Raghavan) writes:
>...
>   My question was simple: Should a program like
>the above give compilation errors? I don't necessarily adopt that style
>of including the same header file in two different functions in the same
>source file; I found it in a Path Pascal compiler I was porting to a Sun
>environment. (Actually, the included file was "stat.h" but the point is 
>the same). Treat it as a question of academic interest only, if you like.

Hmmm... you found that in a PASCAL compiler? Well, then the point is not the
same because PASCAL allows you to restrict the scope of a function/variable
to a function's/procedure's lexical scope. In C, there is no such concept
except the idea of local variables (unless you split your file into multiple
files, one top-level function per file, others static).

With that in mind, I would still say that it doesn't seem to be meaningful
to include standard header files more than once (remember: e.g. typedefs
must not be included more than once). Note the word "standard". Somebody
pointed me to the winner of the last Obfuscated C Contest. This program
apparently used multiple header file inclusion deliberately to get some
weird recursive effect.

Coming back to the original point, I think, you can get dangerous effects
from a number of sources:

o  If the header file defines a struct, your optimizer may decide to optimize
   the structs in different ways for the two functions. Exchanging data won't
   work then (e.g. one function writes the struct to a file, the other reads
   it. Parameter passing is out since the struct isn't defined globally).

o  #define macros will have to be #undef'ed before every definition to avoid
   nasty messages from cpp. You won't be able to distinguish accidental
   redefinitions from intended redefinitions otherwise.

o  If you look at standard header files like <dbm.h>, there are lines
	char    pagbuf[PBLKSIZ];
	char    dirbuf[DBLKSIZ];
   i.e. variable declarations. If you include the header file twice (and
   function-local), you will end up with two copies of the (supposedly)
   shared state variables.

I guess, what you want is some kind of PASCAL-like scoping for C...

-- 
Juergen Wagner		   			gandalf@csli.stanford.edu
						 wagner@arisia.xerox.com

diamond@csl.sony.JUNET (Norman Diamond) (01/30/89)

In article <10991@umn-cs.CS.UMN.EDU> raghavan@umn-cs.cs.umn.edu (Vijay Raghavan) writes:

> main() {
> #include <stdio.h>
> FILE *xx;
> ... 
> }
> proc1() {
> #include <stdio.h>
> FILE *yy;
> ...
> }

In article <9526@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes:

[First three points, good and helpful ones, omitted.]

> The final point is that the standard headers may be included more
> than once with no effect different from being included exactly once.

True, but Mr. Raghavan unwittingly posed a problem.  The effect must
be as if the header were included exactly once, yes, -- but -- as if
the header were included at which place? !

[I have been asked not to complain about inews requiring filler lines]
-- 
Norman Diamond, Sony Computer Science Lab (diamond%csl.sony.jp@relay.cs.net)
  The above opinions are my own.   |  Why are programmers criticized for
  If they're also your opinions,   |  re-inventing the wheel, when car
  you're infringing my copyright.  |  manufacturers are praised for it?

blarson@skat.usc.edu (Bob Larson) (01/30/89)

In article <7360@csli.STANFORD.EDU> gandalf@csli.stanford.edu (Juergen Wagner) writes:
>o  If you look at standard header files like <dbm.h>, there are lines
>	char    pagbuf[PBLKSIZ];
>	char    dirbuf[DBLKSIZ];
>   i.e. variable declarations. If you include the header file twice (and
>   function-local), you will end up with two copies of the (supposedly)
>   shared state variables.

If you include this in two separatly compiled modules, it wouldn't
work either.  It looks like whoever wrote dbm.h forgot that C uses
that def/ref linking model on some systems.  (The declarations MUST be
declared extern in all but one place.)  Adding the extern keyword to
these declarations might be adiquate for some systems, but the
variables realy should be declared without the extern keyword in
exactly one place.  Since dbm.h wasn't written with portibility in
mind, it isn't a good example.

-- 
Bob Larson	Arpa: Blarson@Ecla.Usc.Edu	blarson@skat.usc.edu
Uucp: {sdcrdcf,cit-vax}!oberon!skat!blarson
Prime mailing list:	info-prime-request%ais1@ecla.usc.edu
			oberon!ais1!info-prime-request

gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/31/89)

In article <10995@umn-cs.CS.UMN.EDU> raghavan@umn-cs.cs.umn.edu (Vijay Raghavan) writes:
-In article <9526@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
-<The first point is that the standard headers may be included only
-<outside all function bodies (i.e. at file scope level).
-   May? Does this mean the same as "are required to"?

No, because you're not required to include the header at all (unless,
of course, you want to use something it declares or defines).  You
have official permission to include it ONLY at file scope level.
("may" as in "are allowed to")

-I *know* what the "#ifndef FILE" was attempting to accomplish. All I am
-saying is that the effect is not the same (as without the "#ifndef") when
-the inclusions occur in different mutually non-nesting blocks of the same file.

Thus the injunction against doing that.