Diatribe on uninitialized externs

Doug Gwyn <gwyn> gwyn at brl-tgr.ARPA
Fri Nov 2 14:03:44 AEST 1984


> >...  The last explict initializer is repeated as necessary
> >to fill out the array.
> Oh yeah? Since when? k&r appendix A section 8.6 paragraph #5 says missing
> items get zeroed.

Well, I tried this on a UNIX System V PCC and what Kevin says does
describe its behavior.  I wonder where I got the other idea (which
I suggest is a better rule, but incompatible with current behavior).

> ... Besides, who says I always want the same variant of the union
> initialized. What if one array uses the 'int' element (so I want int zeros),
> and another array uses the pointer element (so I want NULL's)?

In many years of C programming I have never had such a requirement.
Unions are pretty much a kludge for things like memory allocation.
I can think of a general way to specify this type of initialization:
	union	{
		int	a;
		double	b;
		char	*c;
		}
	foo =	{
		,
		3.14159,

		};
using explictly empty members in the initializer (this would apply to
structs as well as unions).  The only incompatibility with current C
that I see here is the slightly different meaning of the final , in
the initializer list.  This solution avoids the ambiguity of using just
a type specifier (which would work for unions but not for structs) and
having to supply explicit member names for initializers (which calls for
a significant change to existing compilers).

> >>       The programmer cannot signal to the reader that a variable is
> >>             deliberately being left un-initialized.
> >Sure he can.  Nothing prevents you from specifying initializers you care
> >about and letting the rest default.  I do this anyway.
> I agree, he can signal deliberately *initialized* ones. But given a declaration
> like
> 	int x;
> I can't tell if he really cares that there is a zero there, if he forgot
> to initialize it, or if he doesn't care what is in it...

Unless you outlaw
	int x;
altogether, or require that there be an explicit initializer SOMEWHERE
among all the load modules (`a la Whitesmiths), you still won't be able
to tell if he wanted the default initialization according to the rules
(assuming a "non-junk" rule), if he doesn't care, or if he forgot.  Using
the same method I suggested above for struct/unions,
	int x = { };
is an explicitly empty initialization showing that the programmer has
thought about the matter and decided that he didn't care what's there.

> The language should not make the "overlay system designer"'s job impossible.
> The language spec doesn't even have to mention overlays. It merely has to
> say what happens to un-initialized variables.

I agree that something definite should be said about the initial contents
of un-initialized variables.  If an overlay system designer finds that
there is no practical way of avoiding clobbering variables (by reloading
their initial values), then he has to give up the idea of transparent
overlay facilities, since it is clear that non-auto/register variables
are intended to retain whatever is stored into them until the program
explicitly stores something else there.  This is perfectly reasonable
and any violation needs to be announced loudly to the user of that
particular overlay system (which should not get in the way when the user
elects NOT to use overlays).  Very few overlay systems (including the one
Ron Natalie and I did for JHU/BRL PDP-11 UNIX) are COMPLETELY transparent
at the source code level, although that is certainly a desirable goal.

> Bear in mind that I use such hostile machines in my regular work, and
> have encountered no problems with the current rules (other than not
> being able to tell deliberate un-initialized from deliberate but implicit
> zero, a problem which is not solved by typed-zero initialization).

If the rule is that uninitialized data is filled with proper-typed zero,
then it seems that you wouldn't have to care which was intended (since
the value of deliberately un-initialized "don't care" storage cannot be
correctly used until it is stored into).  The problems would appear to
be due to trying to follow different rules, for example using specially-
tagged "illegal data" values or "not defined" memory manager traps for
uninitialized data instead of zero.  By the way, I think we should beat
on the hardware designers who keep dreaming up these "helpful" features
without checking with compiler/OS implementers to see what their effects
will be.  If possible, buy more reasonable hardware and TELL the loser
of the competition just what's wrong with his fancy design.

The reason for zero bit pattern is clearly because that is what UNIX
does automatically for "bss" storage.  Not all OSes allow one to use
tricks like this, although the C runtime startoff module could be a
fast loop to initialize "bss" to a zero bit pattern.  Typed zero, though,
in general would have to be initialized by the compiler or by a rather
smart link editor (I can think of some other, incredibly ugly, kludges).

I think I will modify my position:  IF uninitialized data HAS to have
some valid value, then I would (still) recommend 0 of the appropriate
type rather than a 0 bit pattern.  This seems to be compatible with
currently portable C code.  However, if one is willing to drop the
compatibility requirement (apparently the ANSI committee is not), then
I would have uninitialized data contents UNKNOWN, possibly trap-causing,
if they are used before being defined.  That would help stamp out sloppy
coding practices (nothing will completely solve this problem).



More information about the Comp.lang.c mailing list