It's not ridiculous, it's correct. It's nothing to do with mere size,
btw, and everything with logical complexity. If you want an accurate
prediction of how much memory a program could take, you have to be able
to predict which program paths it takes, and that means you have to
predict where it halts.
I think there's a difference of definition here. I believe Malcolm
is referring not to a map of possible program paths, but a static
call graph.
That is, he's referring to a directed graph (it's only a tree for
programs where each function has exactly one caller, and all
functions are reachable from main - not the usual case) where nodes
are functions in the program, and there's an edge from node A to node
B if function A calls function B (directly or through a function
pointer).
Since C does not allow the dynamic construction of function calls,
it's possible to construct such a graph by static analysis of the
source. Whether a given edge will actually be followed in any run of
the program is a separate question (and is equivalent to the Halting
Problem).
For a C program which is non-recursive, the call graph will be
acyclic. If nodes are weighted by their automatic storage
requirement, then the maximum weighted depth of the graph can be
computed.
However, there's no mechanism in standard C for computing the
automatic storage requirement of a function; many interesting C
programs are recursive; and in many cases not all of the source is
available for analysis. And even for programs which satisfy the
latter two conditions and an implementation which supplies sufficient
information for the first, all you know is the upper bound on
automatic storage, which is unlikely to be particularly useful in
most cases. So the prospects for exact analysis of automatic storage
requirements are not good.
As a side note, the non-recursive constraint can be avoided. Any
recursive program can be algorithmically transformed into an
iterative one, by rewriting mutually-recursive functions as a single
function, singly-recursive functions with non-tail recursion as
tail-recursive continuation-passing functions, and finally
tail-recursive functions as iterative. Since C doesn't directly
support continuation-passing style, such a transformation would
require a manual implementation of it - which would mean, in effect,
implementing a CPS-capable language on top of C. Hardly worth the
effort. And all that does is transform auto-storage requirement into
direct-allocated storage requirement anyway, which is a zero-sum or
worse tradeoff in most environments.
--
Michael Wojcik (e-mail address removed)
[After the lynching of George "Big Nose" Parrot, Dr. John] Osborne
had the skin tanned and made into a pair of shoes and a medical bag.
Osborne, who became governor, frequently wore the shoes.
-- _Lincoln [Nebraska] Journal Star_