Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28632 Discussions

incorrect C interface for functions returning a single char (iso_c_binding related)

wim_van_hoydonck1
435 Views

Hi all,

I have been experimenting a little bit with interfacing fortran and python using the iso_c_binding module and the ctypes module. Most things work properly, except for the case where a function returns a single character (c_char), as the example below:

====charfun8.f90=====================================================
function return_char( input ) result( output ) bind(c, name="return_char" )
use iso_c_binding
implicit none
integer(c_int) , intent(in) :: input
character(kind=c_char) :: output
output = achar(input)
print *, "fortran input: ", input
print *, "fortran output: ", output
end function return_char ====charfun8.f90=====================================

Compile this as follows:

$ ifort -shared charfun8.f90 -fPIC -o libcharfun8.so

Calling this function should work from any language that has a C-style interface.

In python, the above fortran function should be callable with the following script:

====pycharfun2.py=====================================
#!/usr/bin/python
# test fortran-python interoperability using ctypes
import numpy as N
import ctypes as C

flib = N.ctypeslib.load_library("libcharfun8",".")

flib.return_char.restype = C.c_char_p
i = C.c_int(110)
ch3 = C.create_string_buffer(1)
ch3 = flib.return_char( C.byref(i) )
====pycharfun2.py=====================================

Executing this script gives a segfault, due to the interface not being what it should be.

$ python pycharfun2.py
Segmentation fault

With a bit of trial and error, the python script can be made working as follows:

====pycharfun.py=====================================
#!/usr/bin/python
# test fortran-python interoperability using ctypes
import numpy as N
import ctypes as C

flib = N.ctypeslib.load_library("libcharfun8",".")

# get character from fortran function
flib.return_char.restype = C.c_char_p
ch = C.create_string_buffer(0)
i = C.c_int(101)
# wrong interface, this is not what the C compiler expects
ch3 = flib.return_char( C.byref(ch) , C.byref(C.c_int(C.sizeof(ch))) , C.byref(i) )
print "in python:", ch3
====pycharfun.py=====================================

$ python pycharfun.py
fortran input: 101
fortran output: e
in python: e

Obviously, the point of BIND(C) is to set the function interface to whatever it is that the C compiler expects, which might or might not be the same as for a non-BIND(C) function. In this case, the foreign function interface created by ifort is wrong.

This is with the following versions of the ifort compiler and python on Fedora 10 (x86_64):

ifort (IFORT) 11.0 20090131 and Python 2.5.2

Could any of the developers tell me if this is fixed in a later version (11.1)? Or should I open a bug report for it?

Greetings,

Wim

0 Kudos
6 Replies
Steven_L_Intel1
Employee
435 Views
I agree with you - I've seen issues similar to this before, but not this particular one. It is not fixed yet. Please feel free to report it. As you say, BIND(C) should provide the same interface C would use, even if it's not what Fortran would use otherwise. In this case, Fortran should not be expecting lengths to be passed. I'm not entirely sure, but does C expect the value to be returned in a register rather than by reference through an argument?
0 Kudos
wim_van_hoydonck1
435 Views
I agree with you - I've seen issues similar to this before, but not this particular one. It is not fixed yet. Please feel free to report it. As you say, BIND(C) should provide the same interface C would use, even if it's not what Fortran would use otherwise. In this case, Fortran should not be expecting lengths to be passed. I'm not entirely sure, but does C expect the value to be returned in a register rather than by reference through an argument?

I've reported this at premier. My knowledge of C is only limited (which is why I was trying to interface fortran with python in the first place), so I honestly do not know what you mean in your last sentence. Anyway, the fortran function that I posted earlier should be callable from C with the following program (which works with g95 and gcc):

====charfun4.c==========================================
#include
char return_char(int *i);
int main()
{
int i;
char c;
i = 64;
c = return_char(&i);
printf("i = %d; return_char(&i) = %cn", i, c);
return 0;
}
====charfun4.c==========================================

Greetings,

Wim

0 Kudos
urbanjost
Beginner
435 Views

Hi all,

I have been experimenting a little bit with interfacing fortran and python using the iso_c_binding module and the ctypes module. Most things work properly, except for the case where a function returns a single character (c_char), as the example below:

====charfun8.f90=====================================================
function return_char( input ) result( output ) bind(c, name="return_char" )
use iso_c_binding
implicit none
integer(c_int) , intent(in) :: input
character(kind=c_char) :: output
output = achar(input)
print *, "fortran input: ", input
print *, "fortran output: ", output
end function return_char ====charfun8.f90=====================================

Compile this as follows:

$ ifort -shared charfun8.f90 -fPIC -o libcharfun8.so

Calling this function should work from any language that has a C-style interface.

In python, the above fortran function should be callable with the following script:

====pycharfun2.py=====================================
#!/usr/bin/python
# test fortran-python interoperability using ctypes
import numpy as N
import ctypes as C

flib = N.ctypeslib.load_library("libcharfun8",".")

flib.return_char.restype = C.c_char_p
i = C.c_int(110)
ch3 = C.create_string_buffer(1)
ch3 = flib.return_char( C.byref(i) )
====pycharfun2.py=====================================

Executing this script gives a segfault, due to the interface not being what it should be.

$ python pycharfun2.py
Segmentation fault

With a bit of trial and error, the python script can be made working as follows:

====pycharfun.py=====================================
#!/usr/bin/python
# test fortran-python interoperability using ctypes
import numpy as N
import ctypes as C

flib = N.ctypeslib.load_library("libcharfun8",".")

# get character from fortran function
flib.return_char.restype = C.c_char_p
ch = C.create_string_buffer(0)
i = C.c_int(101)
# wrong interface, this is not what the C compiler expects
ch3 = flib.return_char( C.byref(ch) , C.byref(C.c_int(C.sizeof(ch))) , C.byref(i) )
print "in python:", ch3
====pycharfun.py=====================================

$ python pycharfun.py
fortran input: 101
fortran output: e
in python: e

Obviously, the point of BIND(C) is to set the function interface to whatever it is that the C compiler expects, which might or might not be the same as for a non-BIND(C) function. In this case, the foreign function interface created by ifort is wrong.

This is with the following versions of the ifort compiler and python on Fedora 10 (x86_64):

ifort (IFORT) 11.0 20090131 and Python 2.5.2

Could any of the developers tell me if this is fixed in a later version (11.1)? Or should I open a bug report for it?

Greetings,

Wim

I believe I am seeing a similar issue; which was discussed in the fortran newsgroup comp.lang.fortran:

#!/bin/sh
set -x
################################################################################
cat > getkey.c <
#include
#include
char getkeyC(void) { /* @(#) read a character from keyboard */
char c;
read(0, &c, 1);
fprintf(stderr,"C:c=%cn",c);
return(c);
}
EOF
################################################################################
cat > f2003.f90 <
! make Fortran/C interface for C routine getkeyC(3C)
module M_getkey
use iso_c_binding
implicit none
public
interface
function getkey() bind(c, name='getkeyC')
use iso_c_binding
implicit none
character(kind=c_char) :: getkey
end function getkey
end interface
end module M_getkey
!=======================================================================--------
program test_getkey
use M_getkey
character :: A
integer :: icount=0;
write(*,*)'begin striking keys -- q to quit; up to 40 characters'
do i10=1,40
A=getkey()
write(*,*)icount,' f03:key=',A,'->',ichar(A)
if(A.eq.'q')stop
enddo
end program test_getkey
EOF
################################################################################
(
exec 2>&1
rm -f getkey.exe getkey.o m_getkey.mod f90.o f77.o M_GETKEY.mod

icc -V
ifort -V
icc -c getkey.c
ifort f2003.f90 getkey.o -o getkey.exe

# demonstrate non-interactive behavior
echo 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'|./getkey.exe|cat -v -e -t

)|tee -a $0
################################################################################
exit
################################################################################
+ rm -f getkey.exe getkey.o m_getkey.mod f90.o f77.o M_GETKEY.mod
+ icc -V
Intel C Intel 64 Compiler Professional for applications running on Intel 64, Version 11.0 Build 20090131 Package ID: l_cproc_p_11.0.081
Copyright (C) 1985-2009 Intel Corporation. All rights reserved.

+ ifort -V
Intel Fortran Intel 64 Compiler Professional for applications running on Intel 64, Version 11.0 Build 20090131 Package ID: l_cprof_p_11.0.081
Copyright (C) 1985-2009 Intel Corporation. All rights reserved.

+ icc -c getkey.c
+ ifort f2003.f90 getkey.o -o getkey.exe
+ echo abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ ./getkey.exe
+ cat -v -e -t
begin striking keys -- q to quit; up to 40 characters$
C:c=a
C:c=b
0 f03:key=^@-> 0$
C:c=c
0 f03:key=^@-> 0$
C:c=d
0 f03:key=^@-> 0$
C:c=e
0 f03:key=^@-> 0$
C:c=f
0 f03:key=^@-> 0$
C:c=g
0 f03:key=^@-> 0$
C:c=h
0 f03:key=^@-> 0$
C:c=i
0 f03:key=^@-> 0$
C:c=j
0 f03:key=^@-> 0$
C:c=k
0 f03:key=^@-> 0$
C:c=l
0 f03:key=^@-> 0$
0 f03:key=^@-> 0$
C:c=m
C:c=n
C:c=o
0 f03:key=^@-> 0$
0 f03:key=^@-> 0$
C:c=p
0 f03:key=^@-> 0$
C:c=q
0 f03:key=^@-> 0$
C:c=r
0 f03:key=^@-> 0$
C:c=s
0 f03:key=^@-> 0$
C:c=t
0 f03:key=^@-> 0$
C:c=u
0 f03:key=^@-> 0$
C:c=v
0 f03:key=^@-> 0$
C:c=w
0 f03:key=^@-> 0$
C:c=x
0 f03:key=^@-> 0$
C:c=y
0 f03:key=^@-> 0$
C:c=z
0 f03:key=^@-> 0$
C:c=A
C:c=B
0 f03:key=^@-> 0$
0 f03:key=^@-> 0$
C:c=C
0 f03:key=^@-> 0$
C:c=D
0 f03:key=^@-> 0$
C:c=E
0 f03:key=^@-> 0$
C:c=F
C:c=G
0 f03:key=^@-> 0$
0 f03:key=^@-> 0$
C:c=H
0 f03:key=^@-> 0$
C:c=I
0 f03:key=^@-> 0$
C:c=J
0 f03:key=^@-> 0$
C:c=K
0 f03:key=^@-> 0$
C:c=L
0 f03:key=^@-> 0$
C:c=M
0 f03:key=^@-> 0$
C:c=N
0 f03:key=^@-> 0$
0 f03:key=^@-> 0$

I believe this would be a duplicate problem report and does not need submitted?


0 Kudos
Steven_L_Intel1
Employee
435 Views
Thanks - you do not need to file a separate report.
0 Kudos
Stephen_D_Intel
Employee
435 Views

I've submitted a problem report on this issue to engineering.

0 Kudos
Steven_L_Intel1
Employee
435 Views
This was fixed in version 12.
0 Kudos
Reply