C'mon, guys!

Wayne Throop throopw at dg_rtp.UUCP
Fri May 30 08:04:46 AEST 1986


> allbery at ncoast.UUCP (Brandon Allbery)

> I concede.  But it wasn't pointer-vs.-array that threw me; f[] and *f are
> identical, whereas f[5] and *f are NOT and neither are f[] = {3} and *f.
> What threw me was getting my insides and outsides confused.  C declarations
> are giving me gray hairs!  Anyone for Modula-2?

I'm for Modula-2 too.  But you don't concede enough, apparently, since
you still think that f[] and *f are the same thing, which they are not,
and you go on to say:

> The declaration is correct, the cast should be to (double **), and MSC is as
> screwed up as everything else I've ever seen from Microsoft.  (So what's
> new?)  I'm interested in knowing why your sys5 passed it without an illegal
> pointer combo message, though.

Which is WRONG, WRONG, WRONG.  The cast should be (double (*)[]).  Many
folks still seem to think that declaring arrays of unknown size is the
same as declaring a pointer.  It is NOT so.  Apparently, I have not
convinced you yet.  Let's see what various tools say about this example:

    1    char *malloc();
    2    void f(){
    3        int (*a)[], (*b)[], (*c)[];
    4        a = (int **)    malloc( (unsigned)sizeof(int)*10 );
    5        b = (int (*)[]) malloc( (unsigned)sizeof(int)*10 );
    6        c = (int *)     malloc( (unsigned)sizeof(int)*10 );
    7    }

Well, what ought to happen here?  The assignment on line 5 is the only
one which has matching types, so everybody ought to complain about the
other two.

Our compiler doesn't raise a peep for any of the three, but this doesn't
surprise me. C compilers most often take a "parts is parts" attitude,
and ignore minor type issues if the intent is "clear".

Our local typechecker says (compressing some whitespace):

    4   inconsistent types discovered
            Types are:  (:POINTER_TO (:ARRAY_OF (:INT) () ()))
            and:        (:POINTER_TO (:POINTER_TO (:INT)))
    6   inconsistent types discovered
            Types are:  (:POINTER_TO (:ARRAY_OF (:INT) () ()))
            and:        (:POINTER_TO (:INT))

Lint, on the other hand, only complains about the assignment on line 6,
saying

    warning: illegal pointer combination
        (6)

So, much to my disgust, lint doesn't catch what I claim is a blatant
error.  So who're ya  gonna believe, me or a stupid program?  :-)
Let's see if we can't induce lint to see a difference between a pointer
and an array with unknown bounds.  Let's consider *this* example:

    1    #include "stdio.h"
    2    void f(){
    3        int (*a)[], **b;
    4        printf( "%d %d\n",
    5            sizeof *a,
    6            sizeof *b );
    7    }

This time, our compiler says

    Error 276 severity 3 beginning on line 5
    You cannot take the size of an array with unknown bounds.

Our local typechecker doesn't raise a peep (it doesn't attempt to
evaluate sizeofs).

And lint, glory be, says

    (5)  warning: sizeof returns value less than or equal to zero

So, lint *does* know the difference between an array of unknown bounds
and a pointer (it correctly complained about applying sizeof to the
array, and allowed the sizeof of the pointer), it just doesn't complain
if you try to assign a pointer-to-a-pointer to a pointer-to-an-array.
That is, lint has a bug, which answers the question as to why lint
doesn't call "illegal pointer combo" on line 4 of the first example.
Further supporting the contention that lint has a bug, it doesn't
complain about this example, which *everyone* should agree is incorrect:

    char *malloc();
    void f(){
        int (*a)[10];
        a = (int **) malloc( (unsigned) sizeof(int)*10 );
    }

In this case, lint apparently thinks that (int (*)[10]) is the same type
as (int **), clearly wrong.

Let's look at one more example.

    #include "stdio.h"
    void main(){
        int ia[10] = {1}, (*a)[] = (int (*)[])ia;
        int i = 2, pi = &i, **b = π
        printf( "%x %x  %d      %x %x  %d\n",
                 a, *a, **a,    b, *b, **b );
    }

This program, when run, prints

    70000a18 70000a18  1      70000a14 70000a12  2

So, a shows the contents of the pointer a, *a is an array name, and
hence shows the address of the first element pointed to by a, and **a is
an integer, the first one in the array *a.  On the other hand b shows
the contents of the pointer b, *b is a pointer, and hence shows the
contents of a second pointer, and **b is an integer, the one pointed to
by *b.

This shows that (*a)[] is talking about two chunks of storage, one being
a pointer to the other, and the other being an array of integers (of
unknown size).  **b, on the other hand, is talking about *three* chunks
of storage, one being a pointer to the second, the second being a
pointer to the third, the third being an integer (or, implicitly, an
array of integers of unknown size).  Note that in both of these cases,
only the *first* of the chunks of storage being talked about is
allocated by the definition of a or b.

Now, have I convinced you all that (*)[] is not the same thing as **,
or must I get out.........  THE RACK!  HA HA HAAAAAA!!!

--
"I didn't expect the bloody Spainish Inquisition."
                                --- Monty Python
-- 
Wayne Throop      <the-known-world>!mcnc!rti-sel!dg_rtp!throopw



More information about the Comp.lang.c mailing list