sizeof() confusion

Karl Heuer karl at ima.isc.com
Mon Nov 5 17:08:50 AEST 1990


In article <9156 at latcs1.oz.au> jacob at latcs1.oz.au (Jacob L. Cybulski) writes:
>	typedef unsigned char Pattern[8];
>	void foo (Pattern x) { ... }

This is related to the pointer-vs-array stuff in the FAQ, which you should
read if you haven't already, but I'll post this answer which is in terms of
your specific example.

The typedef just disguises things; this is equivalent to
	void foo(unsigned char x[8]) { ... }
which, it can be argued, is logically incorrect since C does not allow arrays
to be passed by value.  However, tradition and the ANSI Standard say that this
should be accepted anyway, and *silently rewritten* as
	void foo(unsigned char *x) { ... }
since that's `probably' what the user really meant.  (A better alternative, in
my opinion, would have been to simply forbid array-parameter declarations in
function prototypes until such time as array copy is legalized.)

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

No, there are no `Pattern *' expressions in your code.  The type of x is
`unsigned char *' even if you thought you declared it as `Pattern'.  (This
rewrite is *only* true of formal parameters, and does not apply to any other
kind of declaration.)  You get an error because it's illegal to cast anything
to an array type.

To avoid this type of confusion, I recommend:

(a) *NEVER* declare formal arguments of array type; always use pointer syntax.
    (Some people like to use pointer vs. array syntax to distinguish how they
    intend to use the object, but this causes more confusion than it's worth,
    and besides it doesn't generalize to non-parameter declarations.)

(b) If you want to use opaque types via typedefs, pass them in by reference
    (`Pattern *x' would have produced more consistent results, and is one of
    the few reasonable uses for a pointer-to-entire-array).

(c) If you might have to port to a pre-ANSI implementation that doesn't
    believe in array pointers, then don't use arrays in typedefs either.
    Enclose it in a struct first:
	typedef struct { unsigned char c[8]; } Pattern;
	... x->c[i]; ... /* was x[i] */

>Now is it the fault of my compiler (THINK C) to give me such a hard time,
>is it my bad C programming style, or is it the ANSI standard which has some
>gaping semantic holes?

The compiler is innocent.  I can't really call your style `bad' without
insulting several expert contributors to this group who also happen to use it,
but I always disrecommend it since it does lead to this common pitfall.  I
would classify it as a mistake in Classic C, a botch which X3J11 unfortunately
chose to repeat rather than fix.  (For more details on a possible fix, see
alt.lang.cfutures.)

Karl W. Z. Heuer (karl at ima.isc.com or uunet!ima!karl), The Walking Lint



More information about the Comp.lang.c mailing list