Auto variable with sizeof == 0

Gregory Smith greg at utcsri.UUCP
Tue Feb 3 13:17:17 AEST 1987


In article <4114 at brl-adm.ARPA> escott%deis.uci.edu at icsg.uci.edu writes:
>Somebody recently came to me with a program that worked on a VAX 11/750
>running 4.2BSD but failed on our Sequent Balance 21000 running Dynix 2.1.
> [...] after examining the code in question, I found a construct that
>seems a little strange to me: an automatic variable was declared as a
>"struct foo **bar[]".  "How could this be right?"  I said to myself.  "How
>can you declare an automatic variable that has no size?"
>
>So I wrote a program that contained a similar declaration, and then tried to
>take sizeof( bar ).  Sure enough:
>	warning: sizeof returns 0
>[This from the VAX 11/750 4.2BSD compiler]
>
>Okay, that makes sense.  My question is: is there any reason why you should
>be able to declare an array with zero elements as an automatic variable?
>What's strange is that, on the VAX, the program apparently successfully
>dereferenced bar, both setting a value for "*bar" and then using that value
>later.  How can this be right?  How can "bar" have any value at all, much
>less "*bar"?  If there is no use for a zero-sized automatic variable, how
>come the compiler lets you do it?

Well, *bar is just bar[0], and is of type (struct foo **). There is
indeed no storage reserved for this array element. It is like declaring
'char blat[6]' and then setting "blat[6]='?';". blat[0] through blat[5]
exist, and blat[6] is simply the next char after blat[5]. The C language
does not guarantee what that is. On the vax compiler the 'bar'
declaration reserves zero words for the array 'bar', and then bar[0] is
the word *after* that zero-length array. 

Despite having no length, the array still has an address, and bar[0] is
effectively stored at this same address. Since the array occupies zero
memory, another variable may start in the same place, and bar[0] will
reference the memory occupied by this other variable.

The goof who wrote it probably knew that, with the VAX compiler, setting
*bar would actually set the next declared auto (a little knowledge is a
dangerous thing).  I.e. if it looks like this:
{
	struct foo **bar[];
	char *ptr;
	...
Then ptr and *bar are stored in the same place. Of course this is
non-portable as you have found. Presumably the code using *bar depends
on this shared storage. A quick and dirty fix (fight nasty with nasty?) is

#define bar (struct foo ***)&ptr

instead of the declaration for bar. This will achieve the same effect and
is considerably more portable. It still isn't really correct; the shared
storage should be done either by use of a union, or by casting between the
stored type and the 'struct foo **' type. The choice depends on what is
actually being done with this pointer.

"No one ever said it was going to be easy...."
-- 
----------------------------------------------------------------------
Greg Smith     University of Toronto      UUCP: ..utzoo!utcsri!greg
Have vAX, will hack...



More information about the Comp.lang.c mailing list