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