Point me in the right direction

Ray Butterworth rbutterworth at watmath.waterloo.edu
Sat Feb 18 01:47:09 AEST 1989


In article <1841 at mit-caf.MIT.EDU>, vlcek at mit-caf.MIT.EDU (Jim Vlcek) writes:
> rbutterworth at watmath.waterloo.edu (Ray Butterworth) writes:
> >Another handy style guideline to follow is trying to avoid writing
> >empty [] declarations.  If the [] is empty, then you are talking
> >about an array of unknown size and in the event that you really do
> >want the array there is no way that the compiler will know how big
> >it is.  If you don't know how big an array is, then perhaps you
> >shouldn't be talking about arrays but about pointers.
> 
> No one caught this?  A compiler must be able to determine for itself
> the size of one of the dimensions of an array (I believe the last
> dimension in the case of a superlinear array, no?), if that array is
> to be initialized at compile time, provided that unambiguous
> initializers are provided.   In fact, for an array which is fully
> initialized at compile time, an empty [] declaration is preferable:
> double fund_consts[] = {
>     3.14159265,
>     2.7182818,
>     6.02E23,
> };

I guess I didn't make my context clear.
I didn't mean in cases where the array is actually being defined.
Your examples are perfectly legitimate, and unless one really wants
to explicitly indicate how many elements there should be,
it probably is best to use the empty brackets.

What I was talking about was mostly intended to refer to
parameter declarations.  e.g.
    void func(list) int list[]; { list[0] = 42; }
In this case the compiler does not need to know the dimension of the list.

On the other hand, I'd be concerned about how an external array is used.  e.g.
    extern int vec[];
    for (i=0; vec[i] != END_LIST; ++i) ...
In this case, the list has a special value flagging its end,
so this use is probably ok.
    extern int list[];
    for (i=0; i<LIST_SIZE; ++i) ...
In the second case, the code "knows" how big the list is,
even though the list is defined in a different source file
and someone may have added or deleted a member of that list.
This is not ok.  It would be much better to have
    extern int list[LIST_SIZE];
    for (i=0; i<LIST_SIZE; ++i) ...
or even
    for (i=0; i<sizeof(list)/sizeof(list[0]); ++i) ...
Then lint would notice and complain if the "extern int list[LIST_SIZE]"
referenced something with a different size than the actual list
(which should be defined with "list[]={...}" NOT with "list[LIST_SIZE]=").

> >e.g. use "char **argv;", not "char *argv[];".  Since the compiler
> >will silently convert the second parameter declaration into the
> >first for you, you might as well declare it that way in the first
> >place and avoid confusing yourself and others.
> 
> I wouldn't say this.  I like the use of ``foo *bar[]'' to make it
> clear that ``bar'' does indeed represent an array of pointers, through
> which one might traverse.

So long as you realize that in
    void func(list) int list[]; {extern int vec[]; ...}
the identifiers list and vec have very different types.
vec is an array and list is a pointer.

Many people find this feature to be a cause for confusion.
Here's an example I used a while back to help a local user that
couldn't understand why things were behaving the way they were:

%cat sizeof.c

#include <stdio.h>

test(f, d, s, c, a)
    float f;
    double d;
    short s;
    char c;
    int a[10];
{
    auto float af;
    auto double ad;
    auto short as;
    auto char ac;
    auto int aa[10];

    fprintf(stdout,
        "sizeof autos:  float=%d  double=%d  short=%d  char=%d  int[10]=%d\n",
        (int)sizeof(af), (int)sizeof(ad), (int)sizeof(as),
        (int)sizeof(ac), (int)sizeof(aa));
    fprintf(stdout,
        "sizeof args:   float=%d  double=%d  short=%d  char=%d  int[10]=%d\n",
        (int)sizeof(f), (int)sizeof(d), (int)sizeof(s),
        (int)sizeof(c), (int)sizeof(a));
}

int array[10];

main()
{
    test(0., 0., 0, 0, array);
    return 0;
}

% lint sizeof.c
sizeof.c:
sizeof.c(4): warning: float type changed to double
sizeof.c(8): warning: array[10] type changed to pointer
"fprintf" result is always ignored.

% cc sizeof.c
% ./a.out
sizeof autos:  float=4  double=8  short=2  char=1  int[10]=40
sizeof args:   float=8  double=8  short=2  char=1  int[10]=4

                     ^                                     ^
                     *                                     *

Note that (just as lint said it would be), the parameter declarations
    float f;
    int a[10];
were silently converted by the all too helpful compiler into
    double f;
    int *a;
since the first declarations were types that are not legal as
function arguments.
Since they are impossible as they stand, the compiler tries to
help you by changing them to what you obviously meant.

If you find that confuses you more than it helps you,
you are not alone.

But for good or bad, this is the way the C language is defined to work.

On the other hand, the BSD compiler did not promote the types of
the short and char parameters.  That is probably a bug.



More information about the Comp.lang.c mailing list