sizeof() confusion

Chris Torek chris at mimsy.umd.edu
Mon Nov 5 18:38:01 AEST 1990


In article <9156 at latcs1.oz.au> jacob at latcs1.oz.au (Jacob L. Cybulski)
asks why, given the quoted code, sizeof(Pattern) != sizeof(x):
>typedef unsigned char Pattern[8];
>void foo(Pattern x) {
>/* 0 */	printf("%d\n", sizeof(Pattern);			/* prints 8 */
>/* 1 */	printf("%d\n", sizeof(x));			/* prints 4 */

>The intuition says that sizeof(Pattern) = sizeof(x) regardless of the
>Pattern definition.

Almost true---but *not* regardless of the `x' definition.  (Incidentally,
your example is clearly not out of a working program, as it has a missing
close parenthesis.)

>Well, not in C, if Pattern is an array then it is implemented as a
>pointer so sizeof(x) is a pointer length ....

Bad referent for `it' (core dumped) :-)

In C, there is no such thing as an array parameter.  In a language much
like C, but more strict, compilers would be required to reject any
parameter declaration whose type is `array N of T', for any N and T.
But the C language grants explicit rope with which you may hang yourself:
you may declare any parameter as an array, and the compiler will say
`Oh, that's not an array N of T, that's a pointer to T.  I'll just tidy
up here and pretend you wrote ``pointer to T''.'

But there *are* array objects, and any other declaration of type
`array N of T' really does mean `array N of T'.

Since `typedef' does not make a new type, but rather a synonym for an
old type, `typedef unsigned char Pattern[8];' simply makes `Pattern'
a synonym for `array 8 of unsigned char'.  The compiler sees your
function definition as

	Declare foo as a function returning void, in which
	there is one argument whose type is `array 8 of unsigned
	char'.  Define the function with the contents of the block.

The compiler does its bit with the type of the argument and changes
this to:

	Declare foo as a function returning void, in which
	there is one argument whose type is `pointer to unsigned
	char'.

Thus, you have not actually written `void foo(Pattern x)'.  You have
actually written `void foo(unsigned char *x)'.

>/* 2 */	printf("%d\n", sizeof(*x));			/* prints 1 */

>*x is an address of the first array element so it's length is that
>of its elements

No: `x' is `pointer to unsigned char', so `*x' is `unsigned char', and
sizeof(unsigned char) is 1.

>/* 3 */	printf("%d\n", sizeof((Pattern) x);		/* illegal */

>the cast of x into its type is illegal possibly because x is
>implicitly defined as a (Pattern *)

No, the cast is illegal because there is no such thing an an array value,
and the result of a cast is a value, not an object.  It is therefore
illegal to use an array type (such as `array 8 of unsigned char', aka
`Pattern') in a cast.

>/* 4 */	printf("%d\n", sizeof(*((Pattern *) x));	/* prints 8 */

>finally a convoluted casting and redirection gives you the right answer

Sort of.  `x' is a pointer to array 8 of unsigned char, and can be cast
to a different pointer type (with implementation-defined semantics for
the actual value produced, although here the value is not used and must
be generated by the compiler).  `Pattern *' is another name for
`pointer to array 8 of unsigned char'.  Indirecting (the first unary `*'
above) produces an object---the result of an indirection is always an
object, much as the result of a cast or address-of operator is never an
object---of type `array 8 of unsigned char'.  In a value context, this
object would be transformed into a value of type `pointer to unsigned
char', but unlike an actual function parameter, sizeof() does not call
for a value.  Thus, the object is in object context and remains an array,
and hence has size 8*sizeof(unsigned char) or 8*1 or 8.

>Any answers?

Never use array parameters. :-)

More seriously: for fixed opaque types that happen to be implementable
as an array, you are often better off making the type be a structure
whose only member is an array.  Instead of

	typedef unsigned char Pattern[8];

write

	typedef struct Pattern { unsigned char p_foo[8]; } Pattern;

You now have a compound object which acts more like simple objects,
rather than one that displays the peculiarity of changing type (and
hence also value) whenever it appears in a value context.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 405 2750)
Domain:	chris at cs.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.lang.c mailing list