I am used to Fortran in which I used the namelist sequential read in to get variables out of a file. This allows me to have a file which looks like this
&inputDataList
n = 1000.0 ! This is the first variable
m = 1e3 ! Second
l = -2 ! Last variable
/
where I can name the variable by it's name and assign a value as well as comment afterwards to state what the variable actually is. The loading is done extremely easy by
namelist /inputDataList/ n, m, l
open( 100, file = 'input.txt' )
read( unit = 100, nml = inputDataList )
close( 100 )
Now my question is, is there any similar thing in C? Or would I have to do it manually by chopping the string at the '=' and so on?
Here is a simple example that will let you read Fortran namelists from C. I used the namelist file that you provided in the question, input.txt.
Fortran subroutine nmlread_f.f90 (notice the use of ISO_C_BINDING):
subroutine namelistRead(n,m,l) bind(c,name='namelistRead')
use,intrinsic :: iso_c_binding,only:c_float,c_int
implicit none
real(kind=c_float), intent(inout) :: n
real(kind=c_float), intent(inout) :: m
integer(kind=c_int),intent(inout) :: l
namelist /inputDataList/ n,m,l
open(unit=100,file='input.txt',status='old')
read(unit=100,nml=inputDataList)
close(unit=100)
write(*,*)'Fortran procedure has n,m,l:',n,m,l
endsubroutine namelistRead
C program, nmlread_c.c:
#include <stdio.h>
void namelistRead(float *n, float *m, int *l);
int main()
{
float n;
float m;
int l;
n = 0;
m = 0;
l = 0;
printf("%5.1f %5.1f %3d\n",n,m,l);
namelistRead(&n,&m,&l);
printf("%5.1f %5.1f %3d\n",n,m,l);
}
Also notice that n,m and l need to be declared as pointers in order to pass them by reference to the Fortran routine.
On my system I compile it with Intel suite of compilers (my gcc and gfortran are years old, don't ask):
ifort -c nmlread_f.f90
icc -c nmlread_c.c
icc nmlread_c.o nmlread_f.o /usr/local/intel/composerxe-2011.2.137/compiler/lib/intel64/libifcore.a
Executing a.out produces the expected output:
0.0 0.0 0
Fortran procedure has n,m,l: 1000.000 1000.000 -2
1000.0 1000.0 -2
You can edit the above Fortran procedure to make it more general, e.g. to specify namelist file name and list name from the C program.
I've made a test of above answer under GNU compilers v 4.6.3 and worked perfectly for me. Here's is what I did for the corresponding compilation:
gfortran -c nmlread_f.f90
gcc -c nmlread_c.c
gcc nmlread_c.o nmlread_f.o -lgfortran
Related
This question already has answers here:
Fortran-C interoperability and float arrays
(2 answers)
Closed 2 years ago.
I have alot to learn about Fortran/C interfacing. In a toy code I'm working with, I use C to allocate a double precision array (pointer, actually) for Fortran:
double precision, pointer :: arr(:)
type(C_PTR) :: p
integer :: L=50000
p = alloc_for_fortran(L)
call c_f_pointer(p, arr, [L])
(alloc_for_fortran is a C function I wrote. Seems to work OK. I can show it, but I thought I would try to keep out irrelevant code to keep this post as short as I can.)
I have a simple C function that just gives the element of an array:
void examine(double *arr, int *whichone) {
printf("contents: %lf\n", arr[*whichone-1]);
}
This works fine if I don't define an interface in the Fortran code. For instance, this code
arr(1) = 5.3
examine(arr,1)
gives output:
contents: 5.300000
Now I define an interface for examine, like I'm "supposed" to:
interface
subroutine examine(arr, i) bind(C, name="examine")
use iso_c_binding
double precision, pointer :: arr(:)
integer :: i
end subroutine
end interface
And now the output is incorrect:
contents: 0.000000
Can anyone tell me what I'm doing wrong?
Here's how you do it. Unless you supply a minimal, reproducible example it's difficult to say much more. The main errors in what is shown are trying to pass a Fortran pointer to a C one, when standard Fortran argument mechanisms are sufficient, and declaring the C dummy argument as an assumed shape array, when you should use assumed size as C doesn't support the more advanced Fortran feature
ian#eris:~/work/stack$ cat examine.c
#include <stdio.h>
void examine(double *arr, int *whichone) {
printf("contents: %lf\n", arr[*whichone-1]);
}
ian#eris:~/work/stack$ cat use_examine.f90
Program use_examine
Use iso_c_binding, Only : c_double, c_int
Implicit None
Interface
Subroutine examine( arr, i ) bind( C, name = 'examine' )
Use iso_c_binding, Only : c_double, c_int
Implicit None
Real ( c_double ), Dimension( * ), Intent( In ) :: arr
Integer( c_int ) , Intent( In ) :: i
End Subroutine examine
End Interface
Real( c_double ), Pointer, Dimension( : ) :: a
Allocate( a( 1:2 ) )
a( 1 ) = 5.3_c_double
Call examine( a, 1_c_int )
End Program use_examine
ian#eris:~/work/stack$ gcc --version
gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
ian#eris:~/work/stack$ gcc -c -Wall -Wextra -std=c99 examine.c
ian#eris:~/work/stack$ gfortran -c -Wall -Wextra -fcheck=all -std=f2008 use_examine.f90
ian#eris:~/work/stack$ gfortran use_examine.o examine.o
ian#eris:~/work/stack$ ./a.out
contents: 5.300000
I'm trying to modify this code (gist as back up) to become gfortran-gcc compatible.
I removed the [VALUE] tags
used POINTER with -fcray-pointer flag for gfortran, instead of the [REFERENCE] tag
removed the __stdcall , because tried the #define __stdcall __attribute__((stdcall)) which caused warning: ‘stdcall’ attribute ignored [-Wattributes]
now this is what I have:
C code CMAIN.C:
#include <stdio.h>
extern int FACT_(int n);
extern void PYTHAGORAS_(float a, float b, float *c);
main()
{
float c;
printf("Factorial of 7 is: %d\n", FACT_(7));
PYTHAGORAS_(30, 40, &c);
printf("Hypotenuse if sides 30, 40 is: %f\n", c);
}
the FORTRAN code FORSUBS.FOR:
INTEGER*4 FUNCTION Fact (n)
INTEGER*4 n
INTEGER*4 i, amt
amt = 1
DO i = 1, n
amt = amt * i
END DO
Fact = amt
END
SUBROUTINE Pythagoras (a, b, cp)
REAL*4 a
REAL*4 b
POINTER (cp, c)
REAL*4 c
c = SQRT (a * a + b * b)
END
the Makefile:
all:
gfortran -c FORSUBS.FOR -fcray-pointer
gcc -c CMAIN.C
gfortran -o result.out FORSUBS.o CMAIN.o
rm -rf *.o
clean :
rm -rf *.out *~ *.bak *.o
However I still get the error:
CMAIN.o: In function `main':
CMAIN.C:(.text+0x1d): undefined reference to `FACT_(int)'
CMAIN.C:(.text+0x4c): undefined reference to `PYTHAGORAS_(float, float, float*)'
I would appreciate if you could help me know:
What is the issue and how can I resolve it?
what is the best method to modify the original code to become gcc-gfortran compatible with minimum change.
P.S.1. also shared on Reddit.
P.S.2. operating system and compiler specifications are same as this question.
Fortran passes variables by reference, as mentioned in the first sentences of any Fortran to C tutorial. So you:
Cannot just remove the [VALUE], you should add the modern VALUE attribute or change the C code to pass pointers.
Should not use pointers on the Fortran side of [REFERENCE], but just remove it.
Use the actual name mangling for your compiler, these days normally subroutine_name_ (appended underscore, name is lowercase) or use the modern bind(C, name="binding_name") attribute.
Without modern Fortran, but with VALUE (it is just a PITA without):
INTEGER*4 FUNCTION Fact (n)
INTEGER*4, VALUE :: n
INTEGER*4 i, amt
amt = 1
DO i = 1, n
amt = amt * i
END DO
Fact = amt
END
SUBROUTINE Pythagoras (a, b, c) bind(C)
REAL*4, VALUE :: a
REAL*4, VALUE :: b
REAL*4 c
c = SQRT (a * a + b * b)
END
and than just change your C names to lowercase (pythagoras_, fact_)... With the VALUE attribute you do not need to introduce all those C temporaries you see in the other answer. The bind(C) is required for VALUE to work properly. It will save you from rewriting the code that calls the Fortran procedures.
For best modern experience use bind(C,name="any_name_you_want") to set the exact linkage symbol name.
In addition to my top comments, Fortran passes by reference, so you have to modify the .c and the .for files.
The code below works. There may be a simpler way to declare things, but this should [at least] get you further along. Caveat: I haven't done much fortran since Fortran IV days, so I'm a bit rusty. I'd defer to Vladimir's VALUE solution as a better way to go.
#include <stdio.h>
#if 0
extern int fact_(int n);
extern void pythagoras_(float a, float b, float *c);
#else
extern int fact_(int *n);
extern void pythagoras_(float *a, float *b, float *c);
#endif
int
main(void)
{
float c;
#if 0
printf("Factorial of 7 is: %d\n", fact_(7));
#else
int n = 7;
printf("Factorial of 7 is: %d\n", fact_(&n));
#endif
#if 0
pythagoras_(30, 40, &c);
#else
float a = 30;
float b = 40;
pythagoras_(&a, &b, &c);
#endif
printf("Hypotenuse if sides 30, 40 is: %f\n", c);
return 0;
}
INTEGER*4 FUNCTION Fact (n)
INTEGER*4 n
INTEGER*4 i, amt
amt = 1
DO i = 1, n
amt = amt * i
END DO
Fact = amt
END
SUBROUTINE Pythagoras (a, b, c)
REAL*4 a
REAL*4 b
REAL*4 c
c = SQRT (a * a + b * b)
END
Here is the program output:
Factorial of 7 is: 5040
Hypotenuse if sides 30, 40 is: 50.000000
UPDATE:
I get the same undefined reference error from your code!
Aha!
One thing I didn't mention [because I didn't think it would make a difference] is that I changed the source file names to use all lowercase letters (e.g. CMAIN.C --> cmain.c and FORSUBS.FOR --> forsubs.for)
With that, the output of nm *.o produces:
cmain.o:
U fact_
0000000000000000 T main
U printf
U pythagoras_
forsubs.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_
The change in the fortran source filename doesn't matter too much. But, the C source filename does!
More to the point it's the filename suffix (i.e. .C changed to .c).
This is because gcc will [try to be smart and] look at the suffix to determine which language the file is written in and compile accordingly. For example, gcc -c foo.cpp will compile the file as if it is written in c++ and not c, just as if the command were: g++ -c foo.cpp
Although .cpp is the [more] usual suffix for a c++ filename, an alternate suffix for c++ files is: .C
That is, most projects use the .cpp convention, but some use the .C convention. One of the reasons for preferring .cpp over .C is that Windows filesystems are case insensitive. So, .C and .c would appear the same. However, POSIX systems (e.g. linux, macOSX, iOS, android, etc.) have case sensitive filenames so either convention can be used.
So, gcc -c CMAIN.C will compile as c++. This does c++ style "name mangling" of symbols--not what we want. In c++, the mangling is done to allow "overloading" of function names. That is, two [or more] different functions can have the same name, as long as they use different arguments. For example:
void calc(int val);
void calc(int val1,int val2);
void calc(double fval);
Here is the output of nm *.o if we use CMAIN.C:
CMAIN.o:
0000000000000000 T main
U printf
U _Z11pythagoras_PfS_S_
U _Z5fact_Pi
FORSUBS.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_
Running that file through c++filt to "demangle" the c++ names we get:
CMAIN.o:
0000000000000000 T main
U printf
U pythagoras_(float*, float*, float*)
U fact_(int*)
FORSUBS.o:
0000000000000000 T fact_
0000000000000045 T pythagoras_
So, try to use lowercase filenames if possible [that is recommended best practice]. But, at a minimum, don't use .C
Ultimately I am trying to write an IPC calculator making use of Fortran to calculate and C to pass the data between the two Fortran programs. When I am done it will hopefully look like:
Fortran program to pass input -> Client written in C -> Server written in C -> Fortran program to calculate input and pass ans back
The C client/server part is done, but at the moment I am stuck trying to write a program that takes input in a Fortran program, passes it to a C program that calculates the answer. However, I see som weird behavior.
Fortran program
program calculator
!implicit none
! type declaration statements
integer x
x = 1
! executable statements
x = calc(1,1)
print *, x
end program calculator
C function
int calc_(int *a, int *b ) {
return *a+*b;
}
I have written a main program that verifies that int calc_() does indeed return 2 when called as calc_(1,1) in C, but when I run the program I get the output from Fortran.
I am using this makefile
# Use gcc for C and gfortran for Fortran code.
CC=gcc
FC=gfortran
calc : calcf.o calcc.o
$(FC) -o calc calcf.o calcc.o
calcc.o : calcc.c
$(CC) -Wall -c calcc.c
calcf.o: calcf.f90
$(FC) -c calcf.f90
I cannot for the world figure out why this is the case, and it's driving me mad.
Almost embarrassingly simple. You must declare calc as an integer in Fortran. The working Fortran code is thus
program calculator
!implicit none
! type declaration statements
integer x, calc
x = 1
! executable statements
x = calc(1,1)
print *, x
end program calculator
I've looked around, and though there are a lot of EXC_BAD_ACCESS issues, none of them helped.
I'm using Mountain Lion (OSX 10.8 I think?), and PGI 12.
I can't seem to call fortran functions from C, I've written a simplified case and it seems that I can't pass integers.
My fortran function is:
1 integer function smallFortran(a) result(res) bind(c,name='smallFortran_')
2 !integer function smallFortran(a) result(res)
3
4 use ISO_C_BINDING
5 implicit none
6
7 integer(kind=c_int), intent(IN) :: a
8 !integer, intent(IN) :: a
9
10 print *,'A = ', a
11 res = a;
12
13 endfunction smallFortran
And my C function is,
int main() {
int ier=7;
ier = smallFortran_(8);
}
Build it..
matt#pontus:diffFst$ make
pgcc -c cDoDiffFst.c
PGC-W-0267-#warning -- "Unsupported compiler detected" (/usr/include/sys/cdefs.h: 81)
PGC/x86-64 OSX 12.9-0: compilation completed with warnings
pgcc -g -O0 -traceback -o cDoDiffFst cDoDiffFst.o smallFortran.o -lpgf90 -lpghpf2 -lpgf90rtl -lpgftnrtl -lpghpf_rpm
(I hope that warning isn't what's causing my problems, the PGI user forum responds to this by saying they'll send a newer version of the file, but I haven't been replied to yet. And no idea why PGI requires so many extra libraries to be specified)
When I run it in the debugger..
matt#pontus:diffFst$ gdb cDoDiffFst
(gdb) run
Starting program: /Users/matt/aurams/trunk/utils/diffFst/cDoDiffFst
Reading symbols for shared libraries +............................. done
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000008
0x0000000100001906 in _smallFortran_ (a=Cannot access memory at address 0x8
) at smallFortran.f90:10
10 print *,'A = ', a
(gdb)
I'm totally lost, why can't I send an int? I've tried assigning a value to an integer and sending it, no dice. I've tried it as a subroutine, I've tried it without a return value.. nothing works.
Here is an alternative solution that shows how to write Fortran to match the original C of the question. The key is the value qualifier on the declaration. With the Fortran ISO C Binding you match various ways C passes arguments. You can also do away with underscores in routine names ... that's a purpose of the name keyword of bind.
The C code without the underscore in the call:
int main() {
int ier=7;
ier = smallFortran (8);
}
and the matching Fortran:
function smallFortran(a) result(res) bind(c,name='smallFortran')
use ISO_C_BINDING
implicit none
integer(kind=c_int), intent(IN), value :: a
integer(kind=c_int) :: res
print *,'A = ', a
res = a;
endfunction smallFortran
The error should make clear what's going wrong; smallFortran_ expects its argument to be passed by reference (as are all arguments in fortran -- note that I'm being slightly fast and loose here), and tries to access the data at the pointer 8, which fails. Fix is easy; the function expects a pointer, so give it one:
int main() {
int ier = 7;
int arg = 8;
ier = smallFortran_(&arg);
}
This assumes that the fortran integer type corresponds to a C int with the compilers in question; you may need to make arg a long otherwise.
I'm trying to write a wrapper to use the gsl library with Fortran. I have managed to get a simple wrapper to work - the example from http://www.helsinki.fi/~fyl_tlpk/luento/ohj-13-GSL-e.html
Fortran code
program gsltest
implicit none
real(kind=selected_real_kind(12)) :: a = 0.11, res
external :: glsgateway
call gslgateway(a,res)
write(*,*) 'x', a, 'atanh(x)', res
end program gsltest
c function
#include <gsl/gsl_math.h>
void gslgateway_(double *x, double *res){
*res = gsl_atanh(*x);
}
That's all well and good. However, I'm having problems with a more complicated wrapper. I have the following code modified from an example at http://apwillis.staff.shef.ac.uk/aco/freesoftware.html
c wrapper (rng_initialise.c)
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
static gsl_rng* r;
void rng_initialise__(int* s) {
r = gsl_rng_alloc(gsl_rng_taus);
gsl_rng_set(r, (unsigned long int)(*s));
}
Fortran main (main.f90)
PROGRAM main
integer seed
call system_clock(seed)
WRITE (*,*) 'calling rng_initialise'
call rng_initialise(seed)
END PROGRAM main
which I then compile and link by
gcc -c rng_initialise.c
g95 -c main.f90
g95 -o main main.o rng_initialise.o -L/usr/libs -lgsl
When I run this program, I get no output. However, if I comment out the lines inside rng_initialise
...
void rng_initialise__(int* s) {
// r = gsl_rng_alloc(gsl_rng_taus);
// gsl_rng_set(r, (unsigned long int)(*s));
}
then I get output from the Fortran code (it writes 'calling_rng_initialise' to STDOUT).
So, the problem seems to be the calls to gsl_rng_alloc and gsl_rng_set. But I don't get any error messages, and I don't know why they would prevent the Fortran code from doing anything. Any ideas?
As already suggested, the best way to do this is to use the Fortran ISO C Binding because it will instruct Fortran to use the C calling conventions to match the C routines of the GSL library. The ISO C Binding is part of the Fortran 2003 standard and has been available in many Fortran 95 compilers for several years. As part of the standard it makes interfacing Fortran and C, in both directions, portable and much easier than the OS and compiler dependent hacks that used to be necessary. I recommend ignoring instructions that pre-date the ISO C Binding as obsolete.
Generally you won't need to write any C wrapper code to call the GSL library, only Fortran specifications statements to describe the C routine interfaces to Fortran in Fortran syntax. Here is a simple example that calls the GSL routine gsl_cdf_chisq_Q
program cum_chisq_prob
use iso_c_binding
interface GSL_CummulativeChiSq_Prob_Upper
function gsl_cdf_chisq_Q ( x, nu ) bind ( C, name="gsl_cdf_chisq_Q" )
import
real (kind=c_double) :: gsl_cdf_chisq_Q
real (kind=c_double), VALUE, intent (in) :: x
real (kind=c_double), VALUE, intent (in) :: nu
end function gsl_cdf_chisq_Q
end interface GSL_CummulativeChiSq_Prob_Upper
real (kind=c_double) :: chisq_value
real (kind=c_double) :: DoF
real (kind=c_double) :: Upper_Tail_Prob
write ( *, '( / "Calculates cumulative upper-tail probability for Chi-Square distribution." )' )
write ( *, '( "Input Chisq Value, Degrees of Freedom: " )', advance='no' )
read ( *, * ) chisq_value, DoF
Upper_Tail_Prob = gsl_cdf_chisq_Q ( chisq_value, DoF )
write ( *, '( "Probability is:", 1PG17.10 )' ) Upper_Tail_Prob
stop
end program cum_chisq_prob
Even easier: you can find a pre-written library to allow you to call GSL from Fortran at http://www.lrz.de/services/software/mathematik/gsl/fortran/
Most likely you have the linkage between the two routines wrong in some way. If the stack isn't dealt with correctly when you hop through that interface, dang near anything can happen.
I'm not noticing any code on either the Fortran side or the C side specifying the other's calling convention. I'm not an expert with Gnu Fortran, but I know most compilers will require some kind of note that they should be using another compiler's calling convention, or Bad Things may happen.
With just a little web searching, I see that the G95 Fortran manual (PDF) has a nice long section titled "Interfacing with G95 Programs", that appears to go into this in detail. Just from skimming, it looks like you should be using the BIND(C) attribute on your Fortran function declaration for that C routine.
The problem is with the static gsl_rng* r; defined in your C file. But I do not know/understand why the standard does not allow this. After studying the source file of the fgsl package a little bit, I found a tweak that works. The fortran file random_f.f90
module fgsl
use, intrinsic :: iso_c_binding
implicit none
type, bind(C) :: fgsl_rng_type
type(c_ptr) :: gsl_rng_type_ptr = c_null_ptr
end type fgsl_rng_type
type, bind(C) :: fgsl_rng
type(c_ptr) :: gsl_rng_ptr = c_null_ptr
end type fgsl_rng
end module fgsl
PROGRAM call_fgsl_rndm
use, intrinsic :: iso_c_binding
use fgsl
implicit none
interface
subroutine srndm(seed, t, r) bind(C)
import
integer(C_INT) :: seed
type(fgsl_rng) :: r
type(fgsl_rng_type) :: t
end subroutine srndm
function rndm(r) bind(C)
import
real(C_DOUBLE) :: rndm
type(fgsl_rng) :: r
end function rndm
end interface
type(fgsl_rng) :: r
type(fgsl_rng_type) :: t
integer(C_INT) :: seed
real(C_DOUBLE) :: xi
seed = 1
call srndm(seed, t, r)
xi = rndm(r)
print *, xi
xi = rndm(r)
print *, xi
xi = rndm(r)
print *, xi
END PROGRAM
and the C file random_c.c
#include <gsl/gsl_rng.h>
typedef struct{
gsl_rng *gsl_rng_ptr;
} fgsl_rng;
typedef struct{
gsl_rng_type *gsl_rng_type_ptr;
} fgsl_rng_type;
void srndm(int *seed, fgsl_rng_type* t, fgsl_rng* r) {
t->gsl_rng_type_ptr = (gsl_rng_type *) gsl_rng_mt19937; // cast to remove the const qualifier
r->gsl_rng_ptr = gsl_rng_alloc(gsl_rng_mt19937);
gsl_rng_set(r->gsl_rng_ptr, *seed);
}
double rndm(fgsl_rng* r) {
return gsl_rng_uniform(r->gsl_rng_ptr);
}
Although only the pointers in the structures are used, the introduction of fgsl_rng and fgsl_rng_type is necessary. Otherwise, the program will fail. Unfortunately, I still have no clear idea why it has to work this way.