From: Jared Ahern on
Hello again!

Ok, so I finally put a testcase together. This demonstrates a basic
problem that I have when using iso_c_binding, and calling Fortran
procedures from C. Here is the Fortran side:

MODULE test
USE, INTRINSIC :: iso_c_binding, ONLY: c_float, c_int
IMPLICIT NONE

TYPE, BIND(C) :: foo
REAL(c_float) :: c
END TYPE foo

CONTAINS

TYPE(foo) FUNCTION power_f(a,b) BIND(C)
TYPE(foo), INTENT(IN) :: a
INTEGER(c_int), INTENT(IN) :: b
power_f%c = a%c ** b
END FUNCTION power_f

END MODULE test

Here is the C side:

#include <stdio.h>

typedef struct foo { float c; } foo;
extern foo power_f(const foo* const a,const int* const b);

#ifdef __G95__
extern void g95_runtime_start(int argc, char *argv[]);
extern void g95_runtime_stop();
#endif

int main(int argc, char *argv[]) {
#ifdef __G95__
g95_runtime_start(argc,argv);
#endif
foo fx = {3.0}, fy;
int i = 2;
printf("fx 1 = %f \n",fx.c);
printf("i = %i\n",i);
fy = power_f(&fx,&i);
printf("fx 2 = %f \n",fx.c);
printf("fy = power_f(&fx,&i): %f\n",fy.c);
#ifdef __G95__
g95_runtime_stop();
#endif
return 0;
}

When I compile and run this program, I get output like this (plus an
irrelevant warning):

% gcc -Wall -Wextra -pedantic -std=c89 -D__G95__ -c ctest.c
% g95 -Wall -Wextra -std=f2003 -c flib.F90
% g95 -o ctest.x ctest.o flib.o
fx 1 = 3.000000
i = 2
fx 2 = 1.000000
fy = power_f(&fx,&i): 1.000000

As you can see, the call to power_f not only gave the wrong answer,
but it modified the input argument. My questions would be:

1) Have I done anything incorrectly?
2) What can I do to fix this?

I have a much larger library of which this is an example, and trying
to debug its C bindings has left me quite perplexed. These results
were with linux/x84_64/g95, but linux/x86_64/ifort also has errors,
and osx/ppc64/g95 has problems on similar testcases. In my main
library, I seem to have more problems with types that contain a scalar
real, but I have seen problems with types containing fixed-length
arrays of reals as well. Operations other than exponentiation can
also cause problems.

Any and all thoughts anyone has would be greatly appreciated!

Thanks!
Jared

From: robert.corbett on
On Aug 19, 4:36 pm, Jared Ahern <jared.ah...(a)gmail.com> wrote:
> Hello again!
>
> Ok, so I finally put a testcase together. This demonstrates a basic
> problem that I have when using iso_c_binding, and calling Fortran
> procedures from C. Here is the Fortran side:
>
> MODULE test
> USE, INTRINSIC :: iso_c_binding, ONLY: c_float, c_int
> IMPLICIT NONE
>
> TYPE, BIND(C) :: foo
> REAL(c_float) :: c
> END TYPE foo
>
> CONTAINS
>
> TYPE(foo) FUNCTION power_f(a,b) BIND(C)
> TYPE(foo), INTENT(IN) :: a
> INTEGER(c_int), INTENT(IN) :: b
> power_f%c = a%c ** b
> END FUNCTION power_f
>
> END MODULE test
>
> Here is the C side:
>
> #include <stdio.h>
>
> typedef struct foo { float c; } foo;
> extern foo power_f(const foo* const a,const int* const b);
>
> #ifdef __G95__
> extern void g95_runtime_start(int argc, char *argv[]);
> extern void g95_runtime_stop();
> #endif
>
> int main(int argc, char *argv[]) {
> #ifdef __G95__
> g95_runtime_start(argc,argv);
> #endif
> foo fx = {3.0}, fy;
> int i = 2;
> printf("fx 1 = %f \n",fx.c);
> printf("i = %i\n",i);
> fy = power_f(&fx,&i);
> printf("fx 2 = %f \n",fx.c);
> printf("fy = power_f(&fx,&i): %f\n",fy.c);
> #ifdef __G95__
> g95_runtime_stop();
> #endif
> return 0;
>
> }
>
> When I compile and run this program, I get output like this (plus an
> irrelevant warning):
>
> % gcc -Wall -Wextra -pedantic -std=c89 -D__G95__ -c ctest.c
> % g95 -Wall -Wextra -std=f2003 -c flib.F90
> % g95 -o ctest.x ctest.o flib.o
> fx 1 = 3.000000
> i = 2
> fx 2 = 1.000000
> fy = power_f(&fx,&i): 1.000000
>
> As you can see, the call to power_f not only gave the wrong answer,
> but it modified the input argument. My questions would be:
>
> 1) Have I done anything incorrectly?
> 2) What can I do to fix this?
>
> I have a much larger library of which this is an example, and trying
> to debug its C bindings has left me quite perplexed. These results
> were with linux/x84_64/g95, but linux/x86_64/ifort also has errors,
> and osx/ppc64/g95 has problems on similar testcases. In my main
> library, I seem to have more problems with types that contain a scalar
> real, but I have seen problems with types containing fixed-length
> arrays of reals as well. Operations other than exponentiation can
> also cause problems.
>
> Any and all thoughts anyone has would be greatly appreciated!
>
> Thanks!
> Jared


I got the following results with the Sun Studio 12 f95 compiler:

../a.out
fx 1 = 3.000000
i = 2
fx 2 = 3.000000
fy = power_f(&fx,&i): 9.000000

The program did not compile with the Sun Studio 11 version of the
compiler.

Bob Corbett

From: Tobias Burnus on
> I got the following results with the Sun Studio 12 f95 compiler:
>
> ./a.out
> fx 1 = 3.000000
> i = 2
> fx 2 = 3.000000
> fy = power_f(&fx,&i): 9.000000

I get the same result as sunf95 on x86-64 with gfortran 4.3 (-m32 and -
m64): fy = power_f(&fx,&i): 9.000000
(It does not compile with 4.2 as ISO C Bindings are only supported
since 4.3/2 July 2007.)

Tobias

From: David Thompson on
On Sun, 19 Aug 2007 16:36:52 -0700, Jared Ahern
<jared.ahern(a)gmail.com> wrote:

> Ok, so I finally put a testcase together. This demonstrates a basic
> problem that I have when using iso_c_binding, and calling Fortran
> procedures from C. Here is the Fortran side:

> TYPE, BIND(C) :: foo
> REAL(c_float) :: c
> END TYPE foo

> TYPE(foo) FUNCTION power_f(a,b) BIND(C)
> TYPE(foo), INTENT(IN) :: a
> INTEGER(c_int), INTENT(IN) :: b
> power_f%c = a%c ** b
> END FUNCTION power_f

> Here is the C side:
>
> #include <stdio.h>
>
> typedef struct foo { float c; } foo;
> extern foo power_f(const foo* const a,const int* const b);
>
Aside: it is useless clutter in C to put a 'top-level' const on a
parameter (= dummy) in a _declaration_; these are the ones immediately
adjacent to the name(s). A _pointer to_ const OTOH is important:
extern foo power_f (const foo * a, const int * b);
is EXACTLY the same (and equally correct) to C.

> foo fx = {3.0}, fy;
> int i = 2;
> printf("fx 1 = %f \n",fx.c);
> printf("i = %i\n",i);
> fy = power_f(&fx,&i);
> printf("fx 2 = %f \n",fx.c);
> printf("fy = power_f(&fx,&i): %f\n",fy.c);

> When I compile and run this program, <snip>
> As you can see, the call to power_f not only gave the wrong answer,
> but it modified the input argument. My questions would be:
>
> 1) Have I done anything incorrectly?
> 2) What can I do to fix this?
>
Returning 'struct' types in C has long been an area of implementation
dependence. Most compilers pass the address of a temporary as an
extra, hidden argument (usually first), but some put in register(s) a
struct small enough to fit (as yours does). Sometimes this choice is
selectable by a compiler option. I haven't worked with any significant
Fortran functions returning derived types, but since the issues of
compiling to machine code are the same I would bet that similar
situations arise.

> I have a much larger library of which this is an example, and trying
> to debug its C bindings has left me quite perplexed. These results
> were with linux/x84_64/g95, but linux/x86_64/ifort also has errors,
> and osx/ppc64/g95 has problems on similar testcases. In my main

With which C compiler(s)? gcc? same release as g95? icc? other?

I would first check that the Fortran compiler(s)/version(s)/option(s)
you are using (each) supports BIND(C) _with the specific C
compiler(s)/version(s)/option(s) you are using_.

If that still doesn't work, and no one else familiar with your
specific compilers/versions has offered more specific advice, I would
try looking at the generated assembler (or machine) on both sides for
simple examples like the testcase you posted and see exactly what it's
doing (and thus what it's doing wrong).

> library, I seem to have more problems with types that contain a scalar
> real, but I have seen problems with types containing fixed-length
> arrays of reals as well. Operations other than exponentiation can
> also cause problems.
>
- formerly david.thompson1 || achar(64) || worldnet.att.net
 | 
Pages: 1
Prev: Write to file from DLL
Next: Error LNK2019