Topic: Tolearating ANSI C const float[][] ftn args


Author: pkt@lpi.liant.com (Scott Turner)
Date: Wed, 3 Nov 1993 17:25:15 GMT
Raw View
In article <CFs4FC.DK9@cvbnet.CV.COM>, mswanson@mechmail.cv.com (Mark Swanson) writes:

> extern "C" {
>  float determinant(const float [4][4]);
>  void multiply(float [4][4], const float [4][4]);
> }

> float Matrix::compute_garbage(..) {
>
>  float m1[4][4];
>  float m2[4][4];
>
>  HliFloat f = determinant(m1);  // rejected
>  // VC++ says "error ... Cannot convert arg 1 from float[4][4] to const float[4][4]

Try
  HliFloat f = determinant((const float (*)[4])m1);

which works with VC++, cfront 3.0 and other compilers.

Here's the problem.  In C++ it's OK, for any type T, to pass a
non-const argument of type T to a function with a const T parameter.
For example,

  void det(const T);
  void cg() {
        T m1;
        det(m1);
  }

However, there are several special rules for arrays that interfere with this.
Array types are automatically converted to pointer types, both in expressions
and in function parameter lists.  So in your example what you really have is

  float determinant(const float (*)[4]);
  ...
     HliFloat f = determinant((float (*)[4])m1);

Now, that still may appear to be OK for the reason I give above, if we
take T to be the type
      float (*)[4]       (i.e. pointer to array of 4 floats)

But note that
      const float (*)[4]
is not "const pointer to array of 4 floats".  Instead it is
"pointer to array of 4 const floats".   Since the two pointer types
(of the argument and function parameter) point to different types,
C++ does not allow an implicit conversion.  C has rules which allow
different types to be considered "compatible", but I don't think
that could be applied here to allow this kind of code as C.

Your example is not the only case in which 'const' and arrays don't
mix smoothly in C++.  There's a fair chance that the standards committee
will improve things in this area.  Until we have a finished C++ standard,
I don't think compilers are helping their users, if they refuse to compile
reasonable programs which do something the ARM doesn't fully address.
--
Prescott K. Turner, Jr.
Liant Software Corp. (developers of LPI languages)
959 Concord St., Framingham, MA 01701 USA    (508) 872-8700
UUCP: uunet!lpi!pkt                          Internet: pkt@lpi.liant.com




Author: mswanson@mechmail.cv.com (Mark Swanson)
Date: Sun, 31 Oct 1993 20:47:36 GMT
Raw View
QUESTION:

I must call a C library from C++ whose headers contain a specific prototype
which is increasingly inacessible in newer C++ compilers.  I would like to
know
 a) what is the problem?  (It appears to me to be a misreading of the ARM, but...)
 b) what portable (robust?) workarounds exist for MY C++ code


Note: one vendor has assured me that the problem is "A difference between what
  const means in ANSI C and what it means in C++."

PROBLEM DESCRIPTION

 An ANSI C oriented header file (with a few reluctant concessions to C++) constains
a number of prototypes with arguments such as:

extern "C" {
 float determinant(const float [4][4]);
 void multiply(float [4][4], const float [4][4]);
}


EXACT ERROR MESSAGES:

For C++ functions, several newer (& stricter?) C++ compilers (E.g. DEC's and the Microsoft
VC++/NT compilers reject any attempt to call said C function if one uses a non-const array
as the argument.  No cast seems ato work consistantly.  Example:

float Matrix::compute_garbage(..) {

 float m1[4][4];
 float m2[4][4];

 HliFloat f = determinant(m1);  // rejected
 // VC++ says "error ... Cannot convert arg 1 from float[4][4] to const float[4][4]

 multiply(m1,m2);  // arg2 (only) rejected
 // VC++ says "error ... Cannot convert arg 2 from float[4][4] to const float[4][4]

}

UNDESIREABLE SOLUTION:


These headers are externally & frequently regenerated. I want a solution that does not
require changing them, if at all possible, since without a very good reason that convinces
their C oriented supplier, I will have to edit them everytime a new version of the C library
is released.

A trivial solution (but very undesireable for above and many other reasons) to this problem
involves editing the C library headers thus:

#ifdef __cplusplus
#define CMATRIX void*
#else
#define CMATRIX const float [4][4]
#endif
extern "C" {
 float determinant(CMATRIX);
 void multiply(float [4][4], CMATRIX);
}

With function calls often looking like:

   = deteriminant((CMATRIX) &m1);

Which seems most unlikely to be a general and robust solution.  Can't I have my
typechecking language back?


--
Mark A Swanson     617/275-1800x4927    mswanson@mechmail.cv.com
Computervision  MS 5-2, 14 Crosby Drive, Bedford, MA 01730