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 Corporationkhb@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 Brooksfjhenigman@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, Canadadavea@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