[comp.sys.sgi] Array boundary checking & Fortran <> C translators

tak@aerospace.aero.org (Michael L. Takayama) (02/02/90)

If you are calling Fortran subroutines from C, you may want to be
aware of the following problem which I ran into:

In certain cases, floats do *not* pass correctly to REALs.  This
problem does not occur with ints to INTEGERs nor with doubles to
DOUBLE PRECISIONs.

Example code:

*** main.c ***

main()
{
     double a;
     float b;
     int c;

     a = 1234.5678;		/* Assign values. */
     b = 9876.1234;
     c = 121162;

     /* Call C routine which calls Fortran routine. */

     subtestc(a, b, c);
}

*** subtest.c ***

subtestc(a, b, c)
double a;
float b;
int c;
{
    float temp;

    temp = b;		/* This is my work-around. */

    /* Call the Fortran routine. */

    subtest_(&a, &b, &c, &temp);
}

*** subtest.f ***

      SUBROUTINE SUBTEST(A,B,C,TEMP)
C
      DOUBLE PRECISION A
      REAL B,TEMP
      INTEGER C
C
C     JUST WRITE OUT THE VALUES
C
      WRITE(*,*) A
      WRITE(*,*) B
      WRITE(*,*) C
      WRITE(*,*) TEMP
C
      RETURN
      END

The output of this program is:

1234.567800000000		<<---- ok for double -> DOUBLE PRECISION
6.102790			<<---- WRONG for real -> FLOAT 
   121162			<<---- ok for int -> INTEGER
9876.123			<<---- ok for real -> FLOAT using a
				       temporary variable in subtestc()

Maybe I am doing something illegal here and just got lucky with the
ints and doubles passing correctly (I don't think so - I have
about 60 routines mixing C and Fortran which *do* work correctly), but I
notified the Hotline and they think it is an undiscovered bug in
the Fortran compiler.

With deepest sympathies to my fellow multi-lingual programmers -

Michael L. Takayama
Computer-Aided Engineering Department
The Aerospace Corporation

khb@chiba.kbierman@sun.com (Keith Bierman - SPD Advanced Languages) (02/03/90)

In article <65973@aerospace.AERO.ORG> tak@aerospace.aero.org (Michael L. Takayama) writes:

   If you are calling Fortran subroutines from C, you may want to be
   aware of the following problem which I ran into:

   In certain cases, floats do *not* pass correctly to REALs.  This
   problem does not occur with ints to INTEGERs nor with doubles to
   DOUBLE PRECISIONs.
....
   Maybe I am doing something illegal here and just got lucky with the
   ints and doubles passing correctly (I don't think so - I have
...

The problem is that K&R C implementations traditionally promote all
floats to doubles for both computational and parameter passing
purposes.

ANSI C "fixes" this, by allowing one to create function prototypes
which say explicitly what you want.

SunC (pre-ANSI) fixed this with a compiler option (dangerous, breaks
linkage to many basic C libraries) and via special macros for the C
programmer. 

Other vendors have provided other solutions over the years. Those
doing multi-lingual coding on Unix (pre V.4) may chose to work around
the issue by only attempting to pass double and integer data types
around. 

--
Keith H. Bierman    |*My thoughts are my own. !! kbierman@Eng.Sun.COM
It's Not My Fault   | MTS --Only my work belongs to Sun* kbierman%eng@sun.com
I Voted for Bill &  | Advanced Languages/Floating Point Group            
Opus                | "When the going gets Weird .. the Weird turn PRO"

"There is NO defense against the attack of the KILLER MICROS!"
			Eugene Brooks

fjhenigman@watcgl.waterloo.edu (Frank J. Henigman) (02/03/90)

Your problem arises from the fact that the C compiler does not allow floats
as formal parameters - they are converted to doubles.  Thus, the variable
"b" in "subtestc" is actually a double even though it is declared as float.

The following code demonstrates this behaviour.

-----------------------------------------------------------------------------
bar(fp)
  float *fp;
  {
  printf("%f <--- `wrong'\n", *fp);
  }

foo(fpf)
  float fpf;
  {
  bar(&fpf);
  }

main()
  {
  float f = 9876.1234;
  printf("%f <--- right\n", f);
  foo(f);
  }
-----------------------------------------------------------------------------

9876.123047 <--- right
6.102790 <--- `wrong'

-- 
fjhenigman@watcgl.uwaterloo.ca                       Computer Graphics Lab
fjhenigman@watcgl.waterloo.edu   Frank J. Henigman   University of Waterloo
 ...!watmath!watcgl!fjhenigman                       Waterloo, Ontario, Canada

davea@quasar.wpd.sgi.com (David B. Anderson) (02/03/90)

In article <65973@aerospace.AERO.ORG> tak@aero.UUCP (Michael L. Takayama) writes:
[stuff deleted, some text below rearranged to save space....]
>In certain cases, floats do *not* pass correctly to REALs.  This
>problem does not occur with ints to INTEGERs nor with doubles to
>DOUBLE PRECISIONs.
>main()
>{    double a;      float b;      int c; 
>     a = 1234.5678;		/* Assign values. */
>     b = 9876.1234;
>     c = 121162;
>     /* Call C routine which calls Fortran routine. */
>     subtestc(a, b, c);
>}
>*** subtest.c ***
>subtestc(a, b, c)
>double a;
>float b;
>int c;
>{   float temp;
>    temp = b;		/* This is my work-around. */
>    /* Call the Fortran routine. */
>    subtest_(&a, &b, &c, &temp);
>}
[stuff deleted]
>Maybe I am doing something illegal here and just got lucky with the
            ^^^^^^^^^^^^^^^^^^^^^^^
Yes, you are.
>ints and doubles passing correctly (I don't think so - I have
>about 60 routines mixing C and Fortran which *do* work correctly), but I
>notified the Hotline and they think it is an undiscovered bug in
>the Fortran compiler.

No bug here.  The problem is the way automatic conversions of float to
double are treated in K&R C (See K&R 1, page 205 ``formal parameters
declared float have their declaration adjusted to read double'').
Parameter b in subtestc is called a float but *is really a double*.  Thus,
subtest_(&a,&b,&c,&temp) passes a pointer (&b)  which appears to be a
pointer to a float but is really a pointer to a double.

Consequently dereferencing the pointer results in garbage.

In ANSI C, the behaviour is required to be different: your code would work
with an ANSI C compiler. The reason is that while there would be an
argument which was a float-converted-to-double, b would be a float and the
compiler would generate an assignment in subtestc's entry to assign and
convert the argument to the float b.  (ANSI sec 3.5.4.3, 3.7.1, 3.3.2)

Hope this helps.
Regards,
[ David B. Anderson  Silicon Graphics  (415)335-1548  davea@sgi.com ]

tak@aerospace.aero.org (Michael L. Takayama) (02/06/90)

Thanks for the reminder... guess that it is time to re-read the ol'
K&R!

Verification, please - automatic conversion of float to double occurs
in the parameter declaration of a function in C.  When calling a
Fortran routine from C, this conversion does *not* occur, i.e. a float
passed from C to Fortran should be correctly interpreted as a REAL?

Example:

subtestc()
{
    float a;
   
    a = 1234.5678;
    subtestf_(&a);
}

      SUBROUTINE SUBTESTF(A)
      REAL A

      WRITE(*,*) A

      RETURN
      END


Thanks again (wish you guys were on the Hotline!) -

Michael L. Takayama
Computer-Aided Engineering Department
The Aerospace Corporation