- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
hello
i use intel compiler visual stdio(intel parallel 2015) to compile my project
console ( c source )
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
//#include <iostream>
//#define readfile readfile_
extern void readfile(char*, int*);
int main()
{
int n, count;
char Fname[9];
char Name[10];
strcpy(Fname,"AMIN.for");
fprintf( stderr, "%s\n", Fname);
readfile( Fname, &n, strlen(Fname));
fprintf( stderr, "n = %d\n", n);
// fprintf( stderr, "%s\n", Name);
getch();
getch();
return 0;
}
subroutine ( Lib fortran )
subroutine readfile( fname1, m )
character fname1*(*)
integer m
integer iounit,i
iounit=15
write(*,*) fname1
c10 format (a9)
open(iounit,file = fname1,action='read')
read (iounit,*) m
c20 format (i10)
write(*,*) m
close(iounit)
return
end subroutine
this is my project and i don't have a problem
in this line i have a great problem
readfile( Fname, &n, strlen(Fname) );
i need to change line ( is necessary for me)
readfile( Fname, &n);
is it possible? how to call without lenght character or how to calling convert to run and compile it correctly?
In addition i change "name case interpretation" to "lowercase"
when i compile it , my project cann't open file . i don't khnow why.
how to change setting vs2012 toget to it?
Thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You could just change the prototype on the C side to
void readfile(char*,int*,size_t);
But then I don't know what happens with the trailing NUL character on the Fortran side. Maybe everything goes through OK, or maybe you have to do something like
LEN_FILE = merge(INDEX(fname1,achar(0))-1,len(fname1),scan(fname1,achar(0))>0)
and then subsequently use fname1(1:LEN_FILE) to open the file.
Also I tried some code where the C prototype changed to fit your requirements so the Fortran had to search for the terminating NUL character, and that worked out OK.
#include <stdio.h> #include <stdlib.h> #include <conio.h> #include <string.h> //#include <iostream> //#define readfile readfile_ extern void readfile(char*, int*); int main() { int n, count; char Fname[9]; char Name[10]; strcpy(Fname,"AMIN.for"); fprintf( stderr, "%s\n", Fname); readfile( Fname, &n); fprintf( stderr, "n = %d\n", n); // fprintf( stderr, "%s\n", Name); getch(); getch(); return 0; }
subroutine readfile( fname1, m ) bind(C,name='readfile') use ISO_C_BINDING, only: C_LOC, C_F_POINTER implicit none character, target :: fname1(*) character(:), pointer :: fname3 integer m integer iounit,i i = 0 DO if(fname1(i+1) == achar(0)) exit i = i+1 END DO BLOCK character(i), pointer :: fname2 call C_F_POINTER(C_LOC(fname1),fname2) fname3 => fname2 END BLOCK write(*,*) fname3 10 format (a9) open(newunit=iounit,file = fname3,action='read') read (iounit,*) m 20 format (i10) write(*,*) m close(iounit) return end subroutine
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You could just change the prototype on the C side to
void readfile(char*,int*,size_t);
But then I don't know what happens with the trailing NUL character on the Fortran side. Maybe everything goes through OK, or maybe you have to do something like
LEN_FILE = merge(INDEX(fname1,achar(0))-1,len(fname1),scan(fname1,achar(0))>0)
and then subsequently use fname1(1:LEN_FILE) to open the file.
Also I tried some code where the C prototype changed to fit your requirements so the Fortran had to search for the terminating NUL character, and that worked out OK.
#include <stdio.h> #include <stdlib.h> #include <conio.h> #include <string.h> //#include <iostream> //#define readfile readfile_ extern void readfile(char*, int*); int main() { int n, count; char Fname[9]; char Name[10]; strcpy(Fname,"AMIN.for"); fprintf( stderr, "%s\n", Fname); readfile( Fname, &n); fprintf( stderr, "n = %d\n", n); // fprintf( stderr, "%s\n", Name); getch(); getch(); return 0; }
subroutine readfile( fname1, m ) bind(C,name='readfile') use ISO_C_BINDING, only: C_LOC, C_F_POINTER implicit none character, target :: fname1(*) character(:), pointer :: fname3 integer m integer iounit,i i = 0 DO if(fname1(i+1) == achar(0)) exit i = i+1 END DO BLOCK character(i), pointer :: fname2 call C_F_POINTER(C_LOC(fname1),fname2) fname3 => fname2 END BLOCK write(*,*) fname3 10 format (a9) open(newunit=iounit,file = fname3,action='read') read (iounit,*) m 20 format (i10) write(*,*) m close(iounit) return end subroutine
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Here is one solution which requires little changes to the source code, but is not necessarily portable to compilers other than IFort. It uses the standard C function strlen().
Change the subroutine code to
subroutine readfile( fname1, m ) character fname1*(100) integer m, strlen, iounit character(len=:),allocatable :: fname fname=fname1(1:strlen(fname1)) iounit=15 open(iounit,file = fname,action='read') read (iounit,*) m write(*,*) m close(iounit) return end subroutine
and specify the compiler option /names:lowercase .
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ugh! I'd like to see /names outlawed....
Try this instead:
subroutine readfile( fname1, m ) character fname1*(100) integer m, strlen, iounit external strlen !DEC$ ATTRIBUTES C, REFERENCE, DECORATE, ALIAS:"strlen" :: strlen character(len=:),allocatable :: fname fname=fname1(1:strlen(fname1)) iounit=15 open(iounit,file = fname,action='read') read (iounit,*) m write(*,*) m close(iounit) return end subroutine
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
No offense, but isn't it ugh! all around if we fail to fully recommend standard features for portable, easy-to-follow solutions :-))
@Muhammad S.,
Are you familiar with features in standard Fortran for interoperability with C (as well as a few other "goodies" available in the current standard for I/O)? If not, you may want to look into them - the recommendations in Dr Fortran blog can help. Using the standard features, you can write standard-conforming, portable code as follows:
module m use, intrinsic :: iso_c_binding, only : c_char, c_null_char, c_int, c_ptr, c_f_pointer use, intrinsic :: iso_fortran_env, only : output_unit implicit none private public :: ReadFile !.. Mnemonic constant for an arbitrary limit on file name length integer, parameter :: MAXNAMELEN = 2048 contains subroutine ReadFile( FileNamePtr, n ) bind(C, name="ReadFile") !.. argument list type(c_ptr), intent(in), value :: FileNamePtr integer(kind=c_int), intent(inout) :: n !.. local variables n = -999 blk_read: block character(kind=c_char, len=MAXNAMELEN), pointer :: TmpName character(kind=c_char, len=:), allocatable :: FileName character(len=80) :: ErrMsgIO integer :: LenFileName integer :: Istat integer :: FileUnit logical :: FileExists call c_f_pointer( FileNamePtr, TmpName ) LenFileName = index( TmpName, c_null_char ) - 1 if (LenFileName <= 0) then !.. appropriate messaging action elided return end if FileName = TmpName(1:LenFileName) inquire( FILE=FileName, EXIST=FileExists, IOMSG=ErrMsgIO, IOSTAT=Istat) if (Istat /= 0) then !.. error messaging action elided return else if ( .not. FileExists) then !.. appropriate action elided return end if open( NEWUNIT=FileUnit, FILE=FileName, ACTION="READ", IOMSG=ErrMsgIO, IOSTAT=Istat) if (Istat /= 0) then !.. error messaging action elided return end if read(UNIT=FileUnit, FMT=*, IOMSG=ErrMsgIO, IOSTAT=Istat ) n if (Istat /= 0) then !.. error messaging action elided return end if write(UNIT=output_unit, FMT=*) "From Fortran ReadFile procedure: n = ", n close(UNIT=FileUnit, IOSTAT=Istat) end block blk_read return end subroutine ReadFile end module m
#include <stdio.h> #include <string.h> extern void ReadFile(char*, int*); int main() { int n; char FileName[9]; strcpy(FileName, "AMIN.for"); printf("From C main: FileName = %s\n", FileName); ReadFile(FileName, &n); printf("From C main: n = %d\n", n); getchar(); return 0; }
File AMIN.for:
42
Upon execution with Intel Fortran,
From C main: FileName = AMIN.for From Fortran ReadFile procedure: n = 42 From C main: n = 42 Press any key to continue . . .
P.S.> Not sure why, but the forum is giving a problem: the file AMIN.for just has the number 42 in it, but it is not showing up as such.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear all thanks
Firstly thank for your reply
Ok ,so you say there is no setting in VS ?
I try this insted (Steve Lionel (Intel))
subroutine readfile( fname1, m )
character fname1*(100)
integer m, strlen, iounit
external strlen
!DEC$ ATTRIBUTES C, REFERENCE, DECORATE, ALIAS:"strlen" :: strlen
character(len=:),allocatable :: fname
fname=fname1(1:strlen(fname1))
iounit=15
open(iounit,file = fname,action='read')
read (iounit,*) m
write(*,*) m
close(iounit)
return
end subroutine
Error : forrtl severe (408)
Thanks again
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
this is a very very good & exellent and work thank you i want use fortran 77 . is it possible( "bind" in fort77 isn't unkhnown?) and i want find any way to change code in "c-source" without change "fortran-subroutine" for example define any function for pass them . very thanks
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
In #1 you said that you wanted to call from C a Fortran subroutine with a string as argument but without passing the string length argument that Fortran expects and needs in order to compare the lengths of the actual versus the formal arguments. The dyspepsia-inducing solutions of #3 and #4 do what you asked. However, they work only if you build in "release" mode. If you turn argument consistency checking on, as you probably did in #6, they will cause run-time errors and aborts. Your C function requirement
i need to change line ( is necessary for me):
readfile( Fname, &n);
is it possible? how to call without length character or how to calling convert to run and compile it correctly?
violates the needs of standard Fortran, so it is self-defeating to ask Fortran to check arguments. In particular, if Fortran looks up and uses a length value that was not passed to it, anything can happen.
Your stipulation that you want a solution in F77 came rather late. With some modifications, the solution of #3 could be made acceptable to a F77 compiler, but one is inclined to ask "Do you really want F77? Why?"
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
another question
readfile( Fname, &n, strlen(Fname));
readfile( Fname, &n);
In c-source , is it possible that define one function to get to it or not?
thanks

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page