- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I am trying to learn how to call Fortran from C, I am able to create .so file from C and call it from Ruby On Rails,
the C code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long add(long maxn, double delta, double conf, char *errMsg)
{
long ERR_MSG_LENGTH, answer;
unsigned i;
char * iarr;
iarr = "Hello!";
answer = (long) (maxn+delta+conf);
for (i=0; ((char) iarr) != '\0'; ++i) errMsg = (char) iarr;
errMsg = '\0';
return answer;
}
but when I tried to call Fortran add function from C, I have trouble:
add.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern addsize(long maxn, double delta, double conf, long * sum);
long add(long maxn, double delta, double conf, char *errMsg)
{
long ERR_MSG_LENGTH, answer;
unsigned i;
char * iarr;
iarr = "Hello!";
addsize(maxn, delta, conf, &answer);
for (i=0; ((char) iarr) != '\0'; ++i) errMsg = (char) iarr;
errMsg = '\0';
return answer;
}
addsize.f90:
subroutine addsize( maxn, delta, conf, sum ) bind(c, name='addsize')
use, intrinsic :: iso_c_binding
!use program_constants
implicit none
real(C_LONG), intent(in) :: maxn
real (C_DOUBLE), intent(in) :: delta, conf
real(C_LONG), intent(out) :: sum
sum = maxn + delta + conf;
end subroutine addsize
I compile addsize.f90 as below:
/opt/intel/bin/ifort -c addsize.f90
then compile add.c
gcc -c -shared -fPIC add.c
then create add.so
gcc -shared -fPIC *.o -o add.so
Somehow I couldn't get it to work, is anything wrong in the code? Thanks!
Liz
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
lxh37 wrote:
Well, when I comment out call to Fortran, c code works fine and c code is so simple...
Must something wrong in the interface between c and Fortran.
Liz
@Liz,
As Steve said, it would appear the code you have posted should work, however it is spread across several messages and it's unclear if there are any differences between what you show here and in your actual system which could be causing the problem.
So why don't we try something different? Listed below is a somewhat simplified version of code for what you are trying to do that tries to use standard Fortran and C. It works on my system and gives the output shown below. Can you take this as-is and build execute on your system without any code changes and see what output you get? Post here if your output is different. This might help you figure out what is going on.
module m use, intrinsic :: iso_c_binding, only : c_char, c_null_char, c_long, c_double implicit none private public :: addsize contains function addsize( maxn, delta, conf, msgLen, Msg ) result( answer ) bind(c, name='addsize') !.. argument list integer(c_long), value, intent(in) :: maxn real(c_double), value, intent(in) :: delta real(c_double), value, intent(in) :: conf integer(c_long), value, intent(in) :: msgLen character(kind=c_char,len=1), intent(inout) :: Msg(msgLen) !.. function result integer(c_long) :: answer !.. local variables integer :: i integer(c_long) :: LenMsg character(kind=c_char,len=:), allocatable :: errmsg !.. Message errmsg = "hello" LenMsg = min( msgLen-1, len_trim(errmsg) ) forall (i=1:LenMsg) Msg(i) = errmsg(i:i) end forall !.. Append C null char Msg(LenMsg+1) = c_null_char answer = int( maxn + delta + conf ) ! the sample size return end function addsize end module m
#include <stdio.h> #include <string.h> // function prototypes extern long addsize(long maxn, double delta, double conf, long msgLen, char *Msg); #define ERR_MSG_LENGTH 70 int main() { long result, maxn; double delta, conf; char errMsg[ERR_MSG_LENGTH]; maxn = 1000; delta = 3.2; conf = 6.8; strncpy(errMsg, "There!", (size_t)ERR_MSG_LENGTH); printf("errMsg before calling Fortran function addsize: %s\n", errMsg); result = addsize(maxn, delta, conf, (long)ERR_MSG_LENGTH, errMsg); printf("result=%ld\n", result); printf("errMsg after function call: %s\n", errMsg); return 0; }
errMsg before calling Fortran function addsize: There! result=1010 errMsg after function call: hello Press any key to continue . . .
By the way, you have mixed-mode arithmetic in your Fortran code computing answer that adds an integer with two floating point variables and then casts back to an integer - is this really what you intended? This can cause unexpected behavior unless one is very careful.
P.S.> Are you at Penn State? Go Nittany Lions!
Link Copied
- « Previous
-
- 1
- 2
- Next »
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Well, when I comment out call to Fortran, c code works fine and c code is so simple...
Must something wrong in the interface between c and Fortran.
Liz
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think I find the issue, when pass int * errMsg to Fortran function, inside Fortran function, errmsg can't be
shorter than the length of errMsg (guess if short, some elements are undefined), will cause crash when returned to C.
Liz
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
lxh37 wrote:
Well, when I comment out call to Fortran, c code works fine and c code is so simple...
Must something wrong in the interface between c and Fortran.
Liz
@Liz,
As Steve said, it would appear the code you have posted should work, however it is spread across several messages and it's unclear if there are any differences between what you show here and in your actual system which could be causing the problem.
So why don't we try something different? Listed below is a somewhat simplified version of code for what you are trying to do that tries to use standard Fortran and C. It works on my system and gives the output shown below. Can you take this as-is and build execute on your system without any code changes and see what output you get? Post here if your output is different. This might help you figure out what is going on.
module m use, intrinsic :: iso_c_binding, only : c_char, c_null_char, c_long, c_double implicit none private public :: addsize contains function addsize( maxn, delta, conf, msgLen, Msg ) result( answer ) bind(c, name='addsize') !.. argument list integer(c_long), value, intent(in) :: maxn real(c_double), value, intent(in) :: delta real(c_double), value, intent(in) :: conf integer(c_long), value, intent(in) :: msgLen character(kind=c_char,len=1), intent(inout) :: Msg(msgLen) !.. function result integer(c_long) :: answer !.. local variables integer :: i integer(c_long) :: LenMsg character(kind=c_char,len=:), allocatable :: errmsg !.. Message errmsg = "hello" LenMsg = min( msgLen-1, len_trim(errmsg) ) forall (i=1:LenMsg) Msg(i) = errmsg(i:i) end forall !.. Append C null char Msg(LenMsg+1) = c_null_char answer = int( maxn + delta + conf ) ! the sample size return end function addsize end module m
#include <stdio.h> #include <string.h> // function prototypes extern long addsize(long maxn, double delta, double conf, long msgLen, char *Msg); #define ERR_MSG_LENGTH 70 int main() { long result, maxn; double delta, conf; char errMsg[ERR_MSG_LENGTH]; maxn = 1000; delta = 3.2; conf = 6.8; strncpy(errMsg, "There!", (size_t)ERR_MSG_LENGTH); printf("errMsg before calling Fortran function addsize: %s\n", errMsg); result = addsize(maxn, delta, conf, (long)ERR_MSG_LENGTH, errMsg); printf("result=%ld\n", result); printf("errMsg after function call: %s\n", errMsg); return 0; }
errMsg before calling Fortran function addsize: There! result=1010 errMsg after function call: hello Press any key to continue . . .
By the way, you have mixed-mode arithmetic in your Fortran code computing answer that adds an integer with two floating point variables and then casts back to an integer - is this really what you intended? This can cause unexpected behavior unless one is very careful.
P.S.> Are you at Penn State? Go Nittany Lions!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks! Your way of using c_char is much more elegant, appreciated very much!
I will revise my code to follow yours. It seems that I find out what the problem is and
want to try to see if I can get it working.
PS: We are Nittany Lions...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi, report back. I just patch errmsg in Fortran by " " to have length msgLen-1 (69 in my example). First msgLen-1 elements of iarr will have errmsg cast to int, last element to be 0 as before, the code will not crash anymore. To get whole string, In c code, replace
//for (i=0; ((char) iarr) != '\0'; ++i) errMsg = (char) iarr;
//errMsg = '\0';
with
for(i=0;i<ERR_MSG_LENGTH;i++) errMsg = (char) iarr;
Now it works..
Will try FortranFan's way next week.
Thanks everyone for help. I work in a Linux server without GUI, so it is pretty hard to debug...
Liz
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi, FortranFan:
I tried your way, still crash in Ruby On Rails. I have to do similar thing to patch errmsg "Hello!" by
empty space to make it to be length msgLen-1, then copy it to msg and add c_null_char at the end,
similar as what I did using int * (in this example, I assume msgLen > 7 in C, so I
don't need to handle the case when msgLen is less than 6), my addsize.f90 is below.
Not sure why I need to do this (because of Ruby On Rails platform or Linux?)
integer(c_long) function addsize( maxn, delta, conf, msgLen, msg ) result( answer ) bind(c, name='addsize')
use, intrinsic :: iso_c_binding, only: c_char, c_null_char, c_long, c_double
!use program_constants
implicit none
integer(c_long), value, intent(in) :: maxn
real(c_double), value, intent(in) :: delta, conf
integer(c_long), value, intent(in) :: msgLen
character(kind=c_char, len=1), intent(inout) :: msg(msgLen)
integer(c_long) :: i, lenMsg
character(kind=c_char, len=msgLen-1) :: errmsg
errmsg(1:6) = "Hello!"
do i = 7, msgLen-1
errmsg(i:i) = " "
end do
do i=1,msgLen-1
msg(i) = errmsg(i:i)
end do
msg(msgLen) = c_null_char
answer = int( maxn + delta + conf ); ! the sample size
return
end function addsize
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
lxh37 wrote:
Hi, FortranFan:
I tried your way, still crash in Ruby On Rails. .. Not sure why I need to do this (because of Ruby On Rails platform or Linux?) ..
@Liz,
First, what happens when you try out the Fortran+C code in my Message #24 as-is on your system? If that works ok and the output matches what I show in Message #24, then you can try your modified Fortran code with the C code in Message #24. Only if works as expected do you need to proceed to Ruby On Rails i.e., take it a step at a time.
By the way, what do you mean by, "Not sure why I need to do this (because of Ruby On Rails platform or Linux?)" - do what?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
To run from Ruby On Rails, I have to create .so file and use Ruby package Fiddle to call functions
in the library, can't call C executible from Ruby On Rails, so I use a C wrapper instead.
I have tried my original code (using int * instead in Fortran) in Windows (I used C code containing main
function, similar as yours), it runs fine (I am sure yours will run too). , but it will crash in Ruby On Rails
(in Linux), so I tried to create this simple example to seek help what might go wrong. As I stated, it
works now after I patch the msg string by some empty space...
Liying
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi, FortranFan and all:
I learn to call Fortran directly from Ruby On Rails and it works perfectly, it seems that
previous crash is caused when I have is to pass char * from Fortran to C, then from C to
Ruby On Rails.
Thanks!
Liz
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
thank you mr. Steve

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page
- « Previous
-
- 1
- 2
- Next »