Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.

mixed programing

Muhammad_S_4
Novice
1,417 Views
 

hello

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

0 Kudos
1 Solution
JVanB
Valued Contributor II
1,417 Views

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

 

View solution in original post

0 Kudos
8 Replies
JVanB
Valued Contributor II
1,418 Views

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

 

0 Kudos
mecej4
Honored Contributor III
1,417 Views

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 .

0 Kudos
Steven_L_Intel1
Employee
1,417 Views

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

 

0 Kudos
FortranFan
Honored Contributor III
1,417 Views

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.

0 Kudos
Muhammad_S_4
Novice
1,417 Views

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

0 Kudos
Muhammad_S_4
Novice
1,417 Views

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

0 Kudos
mecej4
Honored Contributor III
1,417 Views

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?"

0 Kudos
Muhammad_S_4
Novice
1,417 Views

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

0 Kudos
Reply