From: steve@taumet.com (Steve Clamage)
Subject: Re: Maximum depth of #if preprocessing directives
Organization: TauMetric Corporation
Date: Wed, 30 Dec 1992 18:49:09 GMT

gordon@sneaky.lonestar.org (Gordon Burditt) writes:

[ Jerry Schwarz writes: ]
>>Just to put my cards on the table.  X3J16/SC22 (C++ standards
>>committee) is sharply divided on whether to have a section on
>>limits.  Some of us, including myself, argue that without such
>>a section any limit is a bug. With such a section arbitrary limits
>>are somehow condoned as suggested by Norman's comment, and we
>>don't want to condone any limits.

>How can you possibly avoid some kind of limit?  Even an implementation
>that uses arbitrary-precision arithmetic for something such as
>#if nesting level is going to have SOME limit, like 
>2^(MAXLONG*sizeof(unsigned long)*CHAR_BIT) (where ^ is an exponentiation
>operator), even if it's outrageously large.  

>Is 32767 an unreasonable limit on the nesting level?  Well, it wouldn't
>cost that much to put the counts in a 32-bit long.  Do I need to go to 
>(about) 2^(2^37)?  (about 137 billion bits in the number)  Or is that 
>too small?

I share Jerry's position, that the Standard should not contain limits.
Let me note that Jerry and I are each compiler implementors, and all our
compilers (from different companies) easily exceed all the limits in the
C Standard.  So we aren't writing out of fear that our compilers will
become invalid.  We are concerned about the consequences to the C and
C++ communities of limits in the Standard.  No other language standard
imposes such limits.

I wrote a paper on this topic for the C++ Committee.  I can't go
into all the details here, but let's consider nesting levels as an
example.

Suppose the Standard says 8 levels.  Some programmers will need more
than 8.  The compiler is not obligated to support more than 8, and if it
doesn't, the user can only beg for more levels.  But since you can't
depend on more than 8, you better not use more than 8 in any program
which is supposed to be portable.  Many programming shops have rules
that you can't write a program which violates any portability rules in
the Standard.  In this way, the "minimum" in the Standard becomes a
real-world "maximum" for programmers.  Programs which need more than 8
levels have to be bent to conform to the limit, becoming harder to
understand and maintain.

You can substitute any small integer for 8, or choose any other limit
in the C standard, and get a similar situation.

Now let's make the limit 32767 for nested includes.  Surely no program
will need more than that.  (Except for poor Pat, who desperately needs
32803, but Pat is out of luck.)  Most (all?) operating systems won't
allow a program (the compiler) to open that many files simultaneously.
This means the compiler has to have a mechanism to close and reopen
files as needed, seeking to a remembered location, when the local limit
on open files has been exceeded.  Sometimes the limit is system-wide,
sometimes each process might have an individual limit; the compiler has
to be able to figure out what the limit is or just have a fixed
conservative limit.

Now we have imposed this elaborate mechanism on all compilers and all
users, who have a bigger and slower compiler as a result.  Most users
will never need so many nested includes, but they all pay the penalty.

Further, there may be some systems on which you can't have 32767 files
at all.  Such a system cannot have a Standard-conforming compiler,
since it can't pass the nested-include test.  The Standard will have
disenfranchised small computer systems; only big systems can have a
validated compiler.

Once again, substitute other numbers and other limits from the Standard
to get similar situations.  Please don't point out that you can
handle the above problem by clever coding and avoid penalties when
the limits aren't exercised.  The overall impact is still to make
compilers bigger and more complex if they must meet artificially
large limits.

Now suppose that the Standard does not mention any limit on nested
includes.  Every real compiler will have a limit of some kind.  If you
need more than that, the compiler vendor can't hide behind the Standard.
Failure to handle an #include is a bug.  One hopes that the vendor will
make as many nested includes available as makes sense on the system.
If you need more than are available, you can lobby the vendor, or find
another one with more capacity.  A vendor who supplies a "conforming"
implementation with only 1 level of include won't have any customers.

Some compiler implementations may find a niche by making small fast
compilers of limited capacity which conform to all explicit requirements
in the Standard.  You might choose the limited-capacity compiler if
you are programming a small system.  The compiler can be validated,
and you can expect your conforming code to work.

When choosing a compiler, there are many things you need to consider.
If you are programming a large system, you need a compiler with large
limits, no matter what the Standard says.  A conforming compiler which
does not meet your needs is of no use.  If you are programming a small
system, you don't care about limits, but you will want a conforming
compiler nontheless.

I favor listing characteristics which a conforming implementation is
required to document.  Just like choosing any other program, you could
then choose a compiler which meets your needs.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com
Newsgroups: comp.std.c