Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

calling a function that returns a c_char from python

13 views
Skip to first unread message

wim

unread,
Mar 26, 2009, 5:12:56 PM3/26/09
to
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 seem to work, but in the example shown below,
something strange happens. If a function gets an integer
as input and returns an integer as a result, everything
works as expected.
However, if a function gets an integer as input and that
integer is converted into a c_char, printing the original
input gives the wrong value and, depending on the
compiler used, the output (a c_char) in python is right or wrong.

If the fortran module is compiled into a shared library:
$ g95 -shared f2py_test.f90 -fPIC -o libf2py_test.so
and python script is run, I get the following output:
$ python f2py_test.py
integer output in fortran : 500
100 500
1761608060
input: 1761608060 iachar(output): 114
r

The problem is with the call to the return_char function,
the input should be '114', but is shown in fortran as
'1761608060', while iachar(output) gives the correct
value inside fortran.

The char returned to python is correct in this case, but
using the intel compiler, I get a vertical bar as output:
$ ifort -shared f2py_test.f90 -fPIC -o libf2py_test.so
$ python f2py_test.py
integer output in fortran : 500
100 500
1761608060
input: 1761608060 iachar(output): 124
|

I am doing something wrong here, or should I just not
try to return c_chars from fortran functions?

Kind regards,

Wim

======fortran test module====f2py_test.f90=====
module f2py_test
! compile with:
! $ g95 -shared f2py_test.f90 -fPIC -o libf2py_test.so
use, intrinsic :: iso_c_binding
implicit none
contains
! returning a character from a function
function return_char( input ) result( output ) bind(c,
name="return_char" )
implicit none
integer(c_int) , intent(in) :: input
character(kind=c_char) :: output
print *, input
output = achar(input)//char(0)
print *, "input: " , input, " iachar(output): ", iachar(output)
end function return_char
! returning an integer from a function
function times_five ( input ) result ( output ) bind(c,
name="times_five")
implicit none
integer(c_int) , intent(in) :: input
integer(c_int) :: output
output = 5 * input
print *, "integer output in fortran :" , output
end function times_five
end module f2py_test
======fortran test module================

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

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

# get integer from fortran function
flib.times_five.restype = C.c_int
i,i2 = C.c_int(100),C.c_int()
i2 = flib.times_five( C.byref(i) )
print i.value,i2

# get character from fortran function
flib.return_char.restype = C.c_char_p
i = C.c_int(114) # result should be 'r'
ch2 = flib.return_char( C.byref(i) )
print ch2
======python test program==============


Richard Maine

unread,
Mar 26, 2009, 5:27:54 PM3/26/09
to
wim <wim.van....@gmail.com> wrote:

> I have been experimenting a little bit with interfacing
> fortran and python using the iso_c_binding module and
> the ctypes module.

I don't really speak python, so I'll have to let others address that
part. I do notice two odd things about the Fortran code.

> character(kind=c_char) :: output

Is that really what the caller expects? I'm more used to C code
expecting things to return a pointer to a character rather than a
character directly. A difference like that is really important.

> output = achar(input)//char(0)

Something is obviously confused here, I'm just not sure what. The above
concatenation, while technically legal, is guaranteed to do nothing
useful. Note that output is declared as a *SINGLE* character.
Achar(input) also returns a single character. The above statement
concatenates a char(0), which is them imediately stripped off by the
assignment to the single character output.

This leaves me unsure whether you actually mean for output to be a
single character or a C string. It also makes me wonder whether you
might not have gotten that entirely straight in your own mind.

--
Richard Maine
email: last name at domain . net
domain: summer-triangle

glen herrmannsfeldt

unread,
Mar 26, 2009, 6:16:33 PM3/26/09
to
wim <wim.van....@gmail.com> wrote:

> I have been experimenting a little bit with interfacing
> fortran and python using the iso_c_binding module and
> the ctypes module.

> Most things seem to work, but in the example shown below,
> something strange happens. If a function gets an integer
> as input and returns an integer as a result, everything
> works as expected.
> However, if a function gets an integer as input and that
> integer is converted into a c_char, printing the original
> input gives the wrong value and, depending on the
> compiler used, the output (a c_char) in python is right or wrong.

(snip)

First, C interoperability might work only for a specific
C compiler to be used with a given Fortran compiler.

It would not surprise me at all that a C function would
never return a char, even if the return type was char.
Often the return value is in a 32 bit register, for
int and any smaller integer type. If your compilers
don't agree on how or where the return value is stored,
you will get strange results.

The C conversion rules are somewhat different from the
Fortran rules. If you aren't used to them you will
be surprised. Try sizeof('x') for a start.

-- glen

wim

unread,
Mar 26, 2009, 6:16:57 PM3/26/09
to
On Mar 26, 10:27 pm, nos...@see.signature (Richard Maine) wrote:

> wim <wim.van.hoydo...@gmail.com> wrote:
> > I have been experimenting a little bit with interfacing
> > fortran and python using the iso_c_binding module and
> > the ctypes module.
>
> I don't really speak python, so I'll have to let others address that
> part. I do notice two odd things about the Fortran code.
>
> >       character(kind=c_char) :: output
>
> Is that really what the caller expects? I'm more used to C code
> expecting things to return a pointer to a character rather than a
> character directly. A difference like that is really important.
>

Yes, I can directly output characters. I have some examples working
that pass characters between fortran and python using subroutines,
those work as expected.

> >       output = achar(input)//char(0)
>
> Something is obviously confused here, I'm just not sure what. The above
> concatenation, while technically legal, is guaranteed to do nothing
> useful. Note that output is declared as a *SINGLE* character.
> Achar(input) also returns a single character. The above statement
> concatenates a char(0), which is them imediately stripped off by the
> assignment to the single character output.

You are right, it should just be:
output = achar(input)

> This leaves me unsure whether you actually mean for output to be a
> single character or a C string. It also makes me wonder whether you
> might not have gotten that entirely straight in your own mind.

Well, the problem is not really the character that is returned from
the
function, but the input to the function. If the return type of the
function
is a character, printing the integer input gives the wrong result.
If the return type of the function is an integer, print the input
gives the
correct result.

Somehow, printing the input gives the right or wrong value depending
on the
return type of the function, which is something I didn't expect...

Greetings,

Wim

glen herrmannsfeldt

unread,
Mar 26, 2009, 6:30:10 PM3/26/09
to
wim <wim.van....@gmail.com> wrote:

> Well, the problem is not really the character that is
> returned from the function, but the input to the function.
> If the return type of the function is a character, printing
> the integer input gives the wrong result.
> If the return type of the function is an integer,
> print the input gives the correct result.

A C function will never have a char as input.
A C expression never has type char or short.

That may not be true of Fortran, and might be
confusing your calls.

-- glen

nm...@cam.ac.uk

unread,
Mar 26, 2009, 6:45:02 PM3/26/09
to
In article <gqgvli$9pv$3...@naig.caltech.edu>,

glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
>
>A C function will never have a char as input.

Don't bet on it. That was true in K&R C, but not in ISO C. You
can't rely on how compilers handle arguments.

>A C expression never has type char or short.

It's not quite that simple.

>That may not be true of Fortran, and might be
>confusing your calls.

That may well be true! You can get thoroughly confused just in C
with arguments and expressions that might be char or short, and
things get a lot hairier when interoperating with Fortran.


Regards,
Nick Maclaren.

James Van Buskirk

unread,
Mar 26, 2009, 9:20:08 PM3/26/09
to
"wim" <wim.van....@gmail.com> wrote in message
news:428d6f69-b9d0-4212...@k2g2000yql.googlegroups.com...

> I have been experimenting a little bit with interfacing
> fortran and python using the iso_c_binding module and
> the ctypes module.

> Most things seem to work, but in the example shown below,
> something strange happens. If a function gets an integer
> as input and returns an integer as a result, everything
> works as expected.
> However, if a function gets an integer as input and that
> integer is converted into a c_char, printing the original
> input gives the wrong value and, depending on the
> compiler used, the output (a c_char) in python is right or wrong.

The problem could lie either on the python side or the Fortran side.
To test the python possibility, you might most simply write out a
C function that does the same as the Fortran function does and
determine whether it behaves as expected.

Assuming it does, we could ask why there should be any problems
the Fortran side and how to diagnose them and work around them.
The problems on the Fortran side crop up from the way passing
character arguments was defined in f77. You could declare a
subroutine like:

SUBROUTINE SUB(X)
CHARACTER*(*) X

Since the calling procedure set the length of dummy argument X and
f77 didn't require the Fortran processor to implement dynamic memory,
the caller would normally pass a pointer to where its actual argument
corresponding to dummy argument X resided and also the length of the
actual argument (by value).

Although this doesn't seem to have anything to do with you example
because a function result is involved rather than a dummy argument,
f77 also introduced the syntax:

CHARACTER*(*) FUNCTION FUN(X)

The length of the result variable FUN would be declared by the caller
and different callers could declare FUN to have different lengths.
Since FUN had to be implementable without dynamic memory, the caller
would have to pass a pointer to where it wanted the result variable
of FUN to lie (within the caller's address space) and the length it
had declared for the result variable. The declaration of a
CHARACTER*(*) function and a function with fixed length result was
indistinguishable in f77 so even fixed-length character functions
would get the same treatment. It's even worse with f95 where the
caller may be required to evaluate a complicated specification
expression (or several such) to determine the result length before
passing, in all probability, the address where it would like the
function to place its result and also the length of the result.

In the early days of C interoperability, some compilers (I remember
ifort as one example) passed around character arguments and function
results the same old f77 way for BIND(C) procedures. Of course, this
meant that a procedure with a character dummy or result simply could
not be interoperable with a C function because it had to pass around
the useless lengths (always 1) and return results by reference instead
of in rax or some more convenient place. And the f03 standard calls
out some situations where C interoperability is not designed to work
and character dummies and results aren't in that list!

I hope that most compilers have rethought this situation and now
pass around character (always *(1)) variables the way the target C
compiler would do, not like an f77 compiler would. This may not be
the case for the version of g95 you are using, and you could test
for this situation by compiling a small bind(C) procedure to
assembly language using the -S -fomit-frame-pointer command line
switched and posting the resulting *.s file here for inspection,
assuming you can't interpret it yourself. A small procedure would
not print out anything, of course.

If it turns out that your problem is on the Fortran side, you could
try downloading the latest g95 to see if Andy has fixed it, try
contacting Andy to see if he intends to fix it, or set the function
result variable to type INTEGER(KIND=C_INT8_T) and transfer any
calculated result to this type as the last step before returning.

--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


Franken Sense

unread,
Mar 27, 2009, 12:13:20 AM3/27/09
to
In Dread Ink, the Grave Hand of nm...@cam.ac.uk Did Inscribe:

I think Ruby's built with MVC++6, which I possess.
--
Frank

I think if you're going to do a movie about Reagan you do it about the fact
that he created the huge deficit, that he armed the mujahadeen, that he
armed Saddam, that he armed Iran, he armed 2/3s of the Axis of Evil, he
funded terrorists in Central America, he was in my mind a terrible
president.
~~ Al Franken, Book TV, on CBS's Reagan movie

wim

unread,
Mar 27, 2009, 6:08:51 AM3/27/09
to
On Mar 27, 2:20 am, "James Van Buskirk" <not_va...@comcast.net> wrote:
> "wim" <wim.van.hoydo...@gmail.com> wrote in message

I got a little further with this. Good thing is that using ifort,
I can correctly return a single character (c_char) to python (see
example below). The bad thing is that the input to that function
(when printed inside the function) is not what is it supposed to be.
I have tested this with shorts, longs, ints, floats and doubles.

No matter what value I use as input (say 110), the following
values are shown when printed inside the function:
c_long: 110, printed: 100205093470601596
c_short: 110, printed: 380
c_int: 110, printed: 1761608060
c_float: 110, printed: 9.6718447E+24
c_double: 110, printed: 5.832899440901411E-302

$ python f2py_test.py
input: 100205093470601596
output: a
a

So, the character in python has the correct value :)
Only 1 problem left: the input to the function has the
wrong value... Would it help if I posted assembly output
for the module shown below (with print statement)?


Wim

========f2py_test.f90==========================


module f2py_test
! compile with:
! $ g95 -shared f2py_test.f90 -fPIC -o libf2py_test.so

! $ ifort -shared f2py_test.f90 -fPIC -o libf2py_test.so


use, intrinsic :: iso_c_binding
implicit none
contains

function return_char( input ) result( output ) bind(c,
name="return_char" )
implicit none

integer(c_long) , intent(in) :: input
character(kind=c_char) :: output
output = "a"
print *, "input: ", input
print *, "output: ", output
end function return_char
end module f2py_test
========f2py_test.f90==========================

========f2py_test.py===========================


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

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

# get character from fortran function
flib.return_char.restype = C.c_char_p

i = C.c_long(110) # result should be 'r'
ch3 = flib.return_char( C.byref(i) )
print ch3
========f2py_test.py===========================

Note that functions that return anyting but a c_char work as
expected (something like the following works properly when
called from python):
=====foo.f90
module foo
use iso_c_binding
contains
function bar(input) result(output)


implicit none
integer(c_int) , intent(in) :: input
integer(c_int) :: output

output = 2*input
end function bar
end module foo
=====foo.f90

Jugoslav Dujic

unread,
Mar 27, 2009, 6:57:42 AM3/27/09
to
wim wrote:
> On Mar 27, 2:20 am, "James Van Buskirk" <not_va...@comcast.net> wrote:
>> "wim" <wim.van.hoydo...@gmail.com> wrote in message

>

> No matter what value I use as input (say 110), the following
> values are shown when printed inside the function:
> c_long: 110, printed: 100205093470601596
> c_short: 110, printed: 380
> c_int: 110, printed: 1761608060
> c_float: 110, printed: 9.6718447E+24
> c_double: 110, printed: 5.832899440901411E-302
>
> $ python f2py_test.py
> input: 100205093470601596
> output: a
> a
>
> So, the character in python has the correct value :)
> Only 1 problem left: the input to the function has the
> wrong value... Would it help if I posted assembly output
> for the module shown below (with print statement)?

Functions returning CHARACTERs (or more fancy stuff, such
as derived types or arrays) can be peculiar in terms of
underlying implementation. That's because the result is
a larger object adn they cannot use the ordinary way to
return it (through registers). Instead, they typically
do something along these lines:

character function foobar(i)

maps to C prototype of:

char* foobar(char* hidden, int* i)

or even:

char* foobar(char* hidden, int lenchar, int* i)

or some similar combination.

Details vary from compiler to compiler, and frankly, I
don't even know how mine does it. I'm guessing that you
actually see an address of something in place of
something else. You may need to analyse the assembly output
and/or do some reverse engineering.

I also don't know what the C interop standard says about
such functions -- are they allowed, is it
implementation-dependent and whether BIND(C) attribute
should affect the underlying ABI. I suppose I'll take
some time to study C interop part in more depth... later.

--
Jugoslav
http://www.xeffort.com

wim

unread,
Mar 27, 2009, 7:06:54 AM3/27/09
to

Some more testing:

Apparently, gfortran doesn't like the above example,
it fails to compile and issues the following error message:

$ gfortran -shared f2py_test.f90 -fPIC -o libf2py_test.so
f2py_test.f90: In function ‘return_char’:
f2py_test.f90:13: error: aggregate value used where an integer was
expected

Anyone knows what that means?

Kind regards,

Wim

wim

unread,
Mar 27, 2009, 9:44:15 AM3/27/09
to

Hi Jugoslav,

Thanks for the help, I have the examples working now (with the intel
compiler).
Apparently, the function prototypes look like this:

char* foobar(char* hidden, int lenchar, int* i)

Good thing is that C strings (char *) also work:

$ ./f2py_test.py
fortran input: 101
fortran output: e
in python: e
fortran input: 16
fortran output: abcdefghijklmnop
in python: abcdefghijklmnop

with the following sources:
====f2py_test.f90=======================


module f2py_test
! compile with:

! $ ifort -shared f2py_test.f90 -fPIC -o libf2py_test.so
use, intrinsic :: iso_c_binding
implicit none
contains

! returning a character from a function

function return_char( input ) result( output ) bind(c,
name="return_char" )
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
! returning character array from a function
function return_chars( input ) result( output ) bind(c,
name="return_chars" )


implicit none
integer(c_int) , intent(in) :: input

character(kind=c_char,len=input) :: output
output = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
print *, "fortran input: ", input
print *, "fortran output: ", output
end function return_chars
end module f2py_test
====f2py_test.f90=======================


====f2py_test.py========================


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

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

# get character from fortran function
flib.return_char.restype = C.c_char_p

ch = C.create_string_buffer(0)
i = C.c_int(101)
ch3 = flib.return_char( C.byref(ch) , C.byref(C.c_int(C.sizeof(ch))) ,
C.byref(i) )
print "in python:", ch3

# get longer character from fortran function
flib.return_chars.restype = C.c_char_p
ch = C.create_string_buffer(0)
ch2 = C.create_string_buffer(16)
i = C.c_int(C.sizeof(ch2))
ch2 = flib.return_chars( C.byref(ch) , C.byref(C.c_int(C.sizeof
(ch))) , C.byref(i) )
print "in python:", ch2
====f2py_test.py========================


Thanks again,

Wim

James Van Buskirk

unread,
Mar 27, 2009, 9:48:54 AM3/27/09
to
"wim" <wim.van....@gmail.com> wrote in message
news:bd989c72-f2e5-4159...@o11g2000yql.googlegroups.com...

> I got a little further with this. Good thing is that using ifort,
> I can correctly return a single character (c_char) to python (see
> example below). The bad thing is that the input to that function
> (when printed inside the function) is not what is it supposed to be.
> I have tested this with shorts, longs, ints, floats and doubles.

> No matter what value I use as input (say 110), the following
> values are shown when printed inside the function:
> c_long: 110, printed: 100205093470601596
> c_short: 110, printed: 380
> c_int: 110, printed: 1761608060
> c_float: 110, printed: 9.6718447E+24
> c_double: 110, printed: 5.832899440901411E-302

> $ python f2py_test.py
> input: 100205093470601596
> output: a
> a

> So, the character in python has the correct value :)
> Only 1 problem left: the input to the function has the
> wrong value... Would it help if I posted assembly output
> for the module shown below (with print statement)?

I hope you realize that what you have shown is not very useful to
someone who is trying to diagnose your problem. Well, I'll just have
to get over it and try to reboot:

C:\gfortran\clf\charfun>type charfun2.f90


function return_char( input ) result( output ) bind(c,name="return_char" )

use ISO_C_BINDING
implicit none
integer(c_long) input
character(kind=c_char) :: output

output = achar(input)
end function return_char

C:\gfortran\clf\charfun>gfortran -S -fomit-frame-pointer charfun2.f90
charfun2.f90: In function 'return_char':
charfun2.f90:7: error: aggregate value used where an integer was expected

C:\gfortran\clf\charfun>type charfun1.f90
function return_char( input ) bind(c,name="return_char" )
use ISO_C_BINDING
implicit none
integer(c_long) input
character(kind=c_char) :: return_char

return_char = achar(input)
end function return_char

C:\gfortran\clf\charfun>gfortran -S -fomit-frame-pointer charfun1.f90

C:\gfortran\clf\charfun>type charfun1.s
.file "charfun1.f90"
.text
.globl _return_char
.def _return_char; .scl 2; .type 32; .endef
_return_char:
subq $24, %rsp
movq %rcx, 32(%rsp)
movq 32(%rsp), %rax
movl (%rax), %eax
movb %al, 14(%rsp)
movzbl 14(%rsp), %eax
movb %al, 15(%rsp)
movzbl 15(%rsp), %eax
addq $24, %rsp
ret

Here's my interpretation of my results:

The result from gfortran of charfun2.f90 indicates a fundamental flaw
in the design of gfortran that I have seen before, in fact I have
seen the same problem in ifort: gfortran handles a result variable
named in a result clause differently than when the function name is
allowed to fall through as the result variable. This means that any
testing of gfortran is useless unless the test code repeats the same
test for both cases. This effectively multiplies the testing burden
by a factor of two, with the expected result that testing is so
incomplete that you will see cases like this again and again where
a failure is noted in one possible coding and not in the other.
The solution would be to stubbornly insist on using the same code
to handle both instances, ripping up the compiler where necessary
to get rid of the duplicate and bad code that must be there. ifort
obviously should be doing that as well because they have the same
problem (generically speaking) but I don't know whether either will
fix this.

Now, for charfun1.f90, which works around the problem as far as
gfortran is concerned: the assembly output indicates to me that
gfortran should work if you eliminate the result clause.

Solution: send gfortran a bug report for charfun2.f90 and send
ifort and g95 bug reports for charfun1.f90. As workarounds,
eliminate the result clause in the gfortran version and force
the result variable to be INTEGER(KIND=C_INT8_T) for ifort and
g95.

It would work like this (for ifort and g95):

C:\gfortran\clf\charfun>type charfun3.f90


function return_char( input ) result( output ) bind(c,name="return_char" )

use ISO_C_BINDING
implicit none
integer(c_long) input
integer(kind=C_INT8_T) :: output
character(kind=c_char) result

result = achar(input)
output = transfer(result,output)
end function return_char

James Van Buskirk

unread,
Mar 27, 2009, 11:20:37 AM3/27/09
to
"wim" <wim.van....@gmail.com> wrote in message
news:553c5230-ac43-4475...@c11g2000yqj.googlegroups.com...

NOOOOoooo....
Your example just shows that you are using a broken Fortran
compiler and it will itself break when the compiler gets fixed.

From N1601.pdf, section 15.2.1:

"Table 15.2 shows the interoperability between Fortran intrinsic
types and C types. A Fortran intrinsic type with particular type
parameter values is interoperable with a C type if the type and
kind type parameter value are listed in the table on the same row
as that C type; if the type is character, interoperability also
requires that the length type parameter be omitted or be
specified by an initialization expression whose value is one."

The function return_chars is therefore nonconforming, as well as the
function return_char being compiled incorrectly. Really, you should
be sending in bug reports before contorting your code to something
which will break when the bugs are eventually fixed.

Jugoslav Dujic

unread,
Mar 27, 2009, 11:40:45 AM3/27/09
to
>> ch2 = flib.return_chars( C.byref(ch) , C.byref(C.c_int(C.sizeof
>> (ch))) , C.byref(i) )
>> print "in python:", ch2
>> ====f2py_test.py========================
>
> NOOOOoooo....
> Your example just shows that you are using a broken Fortran
> compiler and it will itself break when the compiler gets fixed.
>
> From N1601.pdf, section 15.2.1:
>
> "Table 15.2 shows the interoperability between Fortran intrinsic
> types and C types. A Fortran intrinsic type with particular type
> parameter values is interoperable with a C type if the type and
> kind type parameter value are listed in the table on the same row
> as that C type; if the type is character, interoperability also
> requires that the length type parameter be omitted or be
> specified by an initialization expression whose value is one."
>
> The function return_chars is therefore nonconforming, as well as the
> function return_char being compiled incorrectly. Really, you should
> be sending in bug reports before contorting your code to something
> which will break when the bugs are eventually fixed.

Yes, i was sort of hinting at possible compiler bugs, though admittedly
I wasn't too explicit... So the presence of BIND(C) should affect the
underlying ABI (implementation) after all.

What is not clear to me is whether:

character function foobar(i) bind(c)

is allowed to be represented as:

char* foobar(char*, int&)

or it must be just:

char* foobar(int&).

But I suppose I'd better shut up and RTFM.

--
Jugoslav
www.xeffort.com
Please reply to the newsgroup.
You can find my real e-mail on my home page above.

James Van Buskirk

unread,
Mar 27, 2009, 12:14:29 PM3/27/09
to
"Jugoslav Dujic" <jdu...@yahoo.com> wrote in message
news:734admF...@mid.individual.net...

>> NOOOOoooo....

> Yes, i was sort of hinting at possible compiler bugs, though admittedly
> I wasn't too explicit... So the presence of BIND(C) should affect the
> underlying ABI (implementation) after all.

> What is not clear to me is whether:

> character function foobar(i) bind(c)

> is allowed to be represented as:

> char* foobar(char*, int&)

> or it must be just:

> char* foobar(int&).

> But I suppose I'd better shut up and RTFM.

My claim is that it's being tranlated to

char* foobar(char*, int*, int)

So that, for example, if the O.P. recompiled under ifort with the
-mixed_str_len_arg switch, his example might break, depending on
whether ifort passes this switch to BIND(C) procedures.

The issue, as I see it, is that C interoperability should give you
a Fortran translation of:

char return_char(int *i)
{
return (char)(*i);
}

And in fact the translation should be:

function return_char(i) bind(C,name='return_char')
use ISO_C_BINDING
implicit none
integer(C_INT) i
character(C_CHAR) return_char

return_char = achar(i)
end function return_char

Shall we take this for a test drive?

C:\gfortran\clf\charfun>type charfun4.c
#include <stdio.h>

char return_char(int *i);

int main()
{
int i;
char c;

i = 64;
c = return_char(&i);
printf("i = %d; return_char(&i) = %c\n", i, c);

return 0;
}

C:\gfortran\clf\charfun>type charfun5.c
char return_char(int *i)
{
return (char)(*i);
}

C:\gfortran\clf\charfun>gcc -c charfun5.c

C:\gfortran\clf\charfun>gcc charfun4.c charfun5.o -ocharfun4

C:\gfortran\clf\charfun>charfun4
i = 64; return_char(&i) = @

C:\gfortran\clf\charfun>type charfun6.f90
function return_char(i) bind(C,name='return_char')
use ISO_C_BINDING
implicit none
integer(C_INT) i
character(C_CHAR) return_char

return_char = achar(i)
end function return_char

C:\gfortran\clf\charfun>gfortran -c charfun6.f90

C:\gfortran\clf\charfun>gcc charfun4.c charfun6.o -ocharfun4

C:\gfortran\clf\charfun>charfun4
i = 64; return_char(&i) = @

So you can see that it works with gfortran provided we don't
trip over that bug with the result clause. I claim that failure
of my example above to work with ifort or g95 would be a bug in
those compilers.

Richard Maine

unread,
Mar 27, 2009, 12:17:15 PM3/27/09
to
Jugoslav Dujic <jdu...@yahoo.com> wrote:

> So the presence of BIND(C) should affect the
> underlying ABI (implementation) after all.

Yes, of course. That's pretty much the whole point of BIND(C) - to tell
the compiler to do the appropriate thing for the C compiler, which might
or might not be the same thing as would be needed for a simillar
non-BIND(C) Fortran routine.

The usual differences in name decoration (underscores, et al) are one
such area, but there can well be others. For example, as someone
(James?) pointed out, Fortran compilers traditionally pass character
arguements with an extra, "hidden" length argument. They better not do
that for routines with a BIND(C) interface because the C compiler isn't
going to expect that.

wim

unread,
Mar 27, 2009, 4:38:24 PM3/27/09
to

Hi James,

Thanks for the explanation.
I've checked both ifort and g95, with following results
(sources are the same):

with ifort:
$ ifort -c charfun6.f90 -fPIC -o libcharfun6.a
$ gcc charfun4.c libcharfun6.a -ocharfun4 /home/wim/downloads/g95-
install/lib/gcc-lib/x86_64-unknown-linux-gnu/4.0.3/libf95.a
$ gcc charfun4.c libcharfun6.a -ocharfun4
$ ./charfun4
i = 218; return_char(&i) = H
$ ./charfun4
i = 218; return_char(&i) = ▒
$ ./charfun4
i = 218; return_char(&i) = x

not too correct, i guess...

with g95:
$ g95 -c charfun6.f90 -fPIC -o libcharfun6.a -g
$ gcc charfun4.c libcharfun6.a -ocharfun4 /home/wim/downloads/g95-
install/lib/gcc-lib/x86_64-unknown-linux-gnu/4.0.3/libf95.a
$ ./charfun4
Segmentation fault
$ gdb ./charfun4
...
(gdb) run
Starting program: /home/wim/Desktop/test/fortran/fp/charfun4

Program received signal SIGSEGV, Segmentation fault.
0x00000033e3e8494c in _wordcopy_bwd_aligned () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.9-3.x86_64
(gdb) bt
#0 0x00000033e3e8494c in _wordcopy_bwd_aligned () from /lib64/libc.so.
6
#1 0x00000033e3e82d32 in memmove () from /lib64/libc.so.6
#2 0x00000000004018af in return_char (return_char=-8648,
return_char=-8648, i=0x7fffffffde48) at charfun6.f90:7
#3 0x0000000000401844 in main ()

also not very good...

Off to filing bug reports, then.

Kind regards,

Wim

user1

unread,
Mar 28, 2009, 9:19:14 AM3/28/09
to
Franken Sense wrote:
>
> I think Ruby's built with MVC++6, which I possess.

Gosh, maybe I could use that compiler to build me a version of Ruby for
Sparc Linux running on an old Sun Ultra-5 workstation ?


Franken Sense

unread,
Mar 29, 2009, 3:21:13 AM3/29/09
to
In Dread Ink, the Grave Hand of user1 Did Inscribe:

That sounds unlikely.

I only dabble in ruby.
--
Frank

Whining is anger through a small opening.
~~ Al Franken

JB

unread,
Mar 29, 2009, 4:26:06 AM3/29/09
to
On 2009-03-26, wim <wim.van....@gmail.com> wrote:
> Hi all,
>
> I have been experimenting a little bit with interfacing
> fortran and python using the iso_c_binding module and
> the ctypes module.

I'd imagine an easier approach would be to use f2py

http://www.scipy.org/F2py


--
JB

James Van Buskirk

unread,
Mar 29, 2009, 10:03:25 PM3/29/09
to
"Jugoslav Dujic" <jdu...@yahoo.com> wrote in message
news:734admF...@mid.individual.net...

> Yes, i was sort of hinting at possible compiler bugs, though admittedly


> I wasn't too explicit... So the presence of BIND(C) should affect the
> underlying ABI (implementation) after all.

> What is not clear to me is whether:

> character function foobar(i) bind(c)

> is allowed to be represented as:

> char* foobar(char*, int&)

> or it must be just:

> char* foobar(int&).

In my world view it would be:

char foobar(int *i)

The problem arises of how, given that a bind(C) function
doesn't couple as automatically with character functions,
is it possible to do so at all?

We start with a difficult-case character function:

C:\gfortran\clf\charfun>type charstar2.f90
function fun(x)
implicit none
character*(*) fun
integer x

write(fun,'(i0)') len(fun)
fun(len(fun):len(fun)) = achar(x)
end function fun

Slop in a driver program:

C:\gfortran\clf\charfun>type charstar1.f90
program charstar1
implicit none
integer i

do i = 2, 10
call sub1(i)
end do
end program charstar1

subroutine sub1(i)
implicit none
integer i
character(i) fun

write(*,'(a)') fun(i+64)
end subroutine sub1

Compile and run:

C:\gfortran\clf\charfun>gfortran -c charstar2.f90

C:\gfortran\clf\charfun>gfortran charstar1.f90 charstar2.o -ocharstar1

C:\gfortran\clf\charfun>charstar1
2B
3 C
4 D
5 E
6 F
7 G
8 H
9 I
10 J

OK, now we synthesize a C translation:

C:\gfortran\clf\charfun>type charstar3.c
#include <stdio.h>
#include <string.h>

char *fun_(char *pstr, int len, int *pint)
{
int i;

sprintf(pstr, "%d", len);
for(i = strlen(pstr); i < len; i++)
{
pstr[i] = ' ';
}
pstr[len-1] = (char)(*pint);

return pstr;
}

C:\gfortran\clf\charfun>gcc -c charstar3.c

C:\gfortran\clf\charfun>gfortran charstar1.f90 charstar3.o -ocharstar1

C:\gfortran\clf\charfun>charstar1
2B
3 C
4 D
5 E
6 F
7 G
8 H
9 I
10 J

Again success! Note the gfortran puts the hidden function result
length second, immediately after the hidden function result
address. Also, looking at assembly code it didn't seem to me
that gfortran returns a pointer to the function result as
perhaps ifort would do (you could check this) so maybe fun_() should
have been typed as returning void instead of char*.

Now we translate directly to Fortran:

C:\gfortran\clf\charfun>type charstar4.f90
function fun(pstr, len, pint) bind(C, name='fun_')
use ISO_C_BINDING
implicit none
type(C_PTR) fun
type(C_PTR), value :: pstr
integer(C_INT), value :: len
integer(C_INT) pint
character(len=len, kind=C_CHAR), pointer :: str

call C_F_POINTER(pstr, str)
write(str,'(i0)') len
str(len:len) = achar(pint)
fun = pstr
end function fun

C:\gfortran\clf\charfun>gfortran -c charstar4.f90

C:\gfortran\clf\charfun>gfortran charstar1.f90 charstar4.o -ocharstar1

C:\gfortran\clf\charfun>charstar1
2B
3 C
4 D
5 E
6 F
7 G
8 H
9 I
10 J

And so we have successfully made a bind(C) version of our original
function. Looks like we would have to write different versions
for different compilers, but not too difficult.

James Van Buskirk

unread,
May 11, 2009, 1:00:49 PM5/11/09
to
"wim" <wim.van....@gmail.com> wrote in message
news:553c5230-ac43-4475...@c11g2000yqj.googlegroups.com...

> # get character from fortran function
> flib.return_char.restype = C.c_char_p
> ch = C.create_string_buffer(0)
> i = C.c_int(101)
> ch3 = flib.return_char( C.byref(ch) , C.byref(C.c_int(C.sizeof(ch))) ,
> C.byref(i) )
> print "in python:", ch3

An old thread, but since you are propagating this error elsewhere I
thought to correct it in this forum at least. I'm pretty sure that
the second argument to flib.return_char should be by value rather
than by reference. If you wrote a Fortran function that read the
string length:

function rc(i)
character(*) rc
integer i

write(*,*) len(rc), i
rc(1:1) = achar(i)
end function rc

You could see the difference. Passing the string length by
reference probably results in the function reading the
address as the result length. If the function doesn't use the
passed length it may ignore it. If it does use the passed length
as above the result may be very long indeed.

0 new messages