Conformant Arrays in C

David Hough dgh%dgh at Sun.COM
Sat Feb 20 03:54:56 AEST 1988


I have been wondering about a problem that's been discussed,
often incorrectly, in comp.lang.c.  The problem is easy enough
to understand if you've ever written linear algebra software,
but the correct "in the spirit of C" solution wasn't clear
to me.

Fortunately Richard O'Keefe has volunteered some ideas.
I'd appreciate feedback on them.  If you're simply opposed
to making C suitable for scientific programming, the net has
already heard from you, so you needn't repeat your views,
but if you have ideas for better syntax or better ways to
achieve the goal, please speak up.  The following is one of my
comments on the January 1988 X3J11 draft for ANSI C,
followed by the proposed solution.


Comment #24, Section 3.5.4.2:   fix arrays

     I know no C translation that's as clear as the  follow-
ing Fortran code:

        SUBROUTINE MATMUL(X,LX,Y,LY,Z,LZ,NX,NY,NZ)
        REAL X(LX,*),Y(LY,*),Z(LZ,*)
        DO 1 I=1,NX
                DO 2 J=1,NZ
                SUM=0
                        DO 3 K=1,NY
 3                      SUM=SUM+X(I,K)*Y(K,J)
 2              Z(I,J)=SUM
 1      CONTINUE
        END

Code like this is at the heart of most of the major portable
Fortran  libraries  of  mathematical software developed over
the last twenty years. The declared leading dimensions of X,
Y, and Z are not known until runtime.

     The Draft, like traditional C, disallows the equivalent

        void matmul(x,lx,cx,...)
        int lx, cx;
        double x[lx][cx] ;

unless lx and cx are  known  at  compile  time.   Equivalent
functionality  can  be  obtained  by  treating all arrays as
one-dimensional and doing the  subscripting  "by  hand",  so
that  it's harder to get right and harder to optimize.  Fix-
ing C's handling of arrays would be a far worthier task  for
the  X3J11 experts than (for instance) specifying details of
the math library.  Maybe there's some good fundamental  rea-
son  why  variables  are disallowed as array dimensions; C's
treatment of arrays has always been confusing.

     Note that the section numberings in the Draft  and  Ra-
tionale are out of synch in the declarations subchapter.

     Recommendation: Fix, by language design  if  necessary,
the  treatment  of  arrays  in  C  to  properly  accommodate
multiply-dimensioned arrays whose  dimensions  vary  at  run
time.   The  goal is not to duplicate Fortran's features ex-
actly, but rather to insure that portable linear algebra li-
braries are as easy to create in C as in Fortran.

Array proposal
----- --------

     Richard O'Keefe has kindly provided the following  out-
line of how an array facility might work in C:

     The  smallest  possible  change  would  be  "conformant
arrays" much as in ISO Pascal or in Turing, where the param-
eter declaration was something like

        void matmul(double a[p][q], b[q][r], c[p][r])
            {
                int i, j, k;
                double t;
                for (i = p; --i >= 0; )
                    for (j = r; --j >= 0; ) {
                        t = 0.0;
                        for (k = q; --k >= 0; ) t *= a[i][j]*b[j][k];
                        c[i][j] = t;
                    }
            }

If p, q, and r are #defined to be constant expressions, this
is already legal, so we need one more thing to indicate that
p,q,r are being defined here, not used.  Consider  the  fol-
lowing:

        declarator:     ...
                  |     declarator '[' subscript_spec ']'
                  ;

        subscript_spec: '?' identifier
                      | constant_expression
                      | /* empty */
                      ;

where  /*  empty  */  is   only   allowed   as   the   first
subscript_spec,  and  ?id  is  only  allowed  in  a function
header.  To avoid having to specify what happens if  ?x  ap-
pears several times but the arguments don't agree with that,
make it illegal, so the first suggestion would  have  to  be
written

        void matmul(double a[?ar][?ac], /* ar >= p, ac >= q */
                    double b[?br][?bc], /* br >= q, bc >= r */
                    double c[?cr][?cc], /* cr >= p, cc >= r */
                    int p,              /* 0 <= p <= min(ar,cr) */
                    int q,              /* 0 <= q <= min(ac,br) */
                    int r)              /* 0 <= r <= min(bc,cc) */
            {
                int i, j, k;
                double t;
                for (i = p; --i >= 0; )
                    for (j = r; --j >= 0; ) {
                        t = 0.0;
                        for (k = q; --k >= 0; ) t *= a[i][j]*b[j][k];
                        c[i][j] = t;
                    }
            }

A conformant array may be passed as a parameter to  a  func-
tion  provided  the function's prototype was visible to con-
firm that a conformant array parameter was intended.

     The simplest way of treating sizeof is to rule it  out:
if  the  description of 'a' involves any ?s, you can't apply
sizeof to it.  So given a parameter

        float fred[?f1][?f2][10];

sizeof fred and sizeof fred[1] would be illegal, but  sizeof
fred[1][2] and sizeof fred[1][2][3] would be legal.


David Hough

ARPA: dhough at sun.com
UUCP: {ucbvax,decvax,decwrl,seismo}!sun!dhough



More information about the Comp.lang.c mailing list