Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28457 Discussions

Passing a fixed length string from C++ to Fortran subroutine

Dominic_C_1
Beginner
1,574 Views

I want to pass a fixed length string from C++ to Fortran subroutine, and assign it to a string within that subroutine (to be used elsewhere), and am having some difficulty.

Below is the shortened code. 

character(len=10) :: venue

subroutine Initialisation(venue_name)
   character(len=10), intent(in)                               :: venue_name
   
   !DEC$ ATTRIBUTES DLLEXPORT :: INITIALISATION
   
   !How do I assign the string here?
   venue = venue_name

end subroutine Initialisation

I have tried with various different ways of doing it, but keep getting runtime errors. With the above example I get "Dummy character variable "VENUE_NAME" has length 10 which is greater than actual variable length -539671288"

0 Kudos
1 Solution
IanH
Honored Contributor II
1,574 Views
MODULE m
  IMPLICIT NONE
  CHARACTER(:), ALLOCATABLE :: venue
CONTAINS
  SUBROUTINE Initialisation(venue_name, length) BIND(C, NAME='Initialisation')
    USE ISO_C_BINDING, ONLY: C_CHAR, C_INT
    CHARACTER(KIND=C_CHAR), INTENT(IN) :: venue_name(*)
    INTEGER(C_INT), INTENT(IN), VALUE :: length
    INTEGER :: i
    ALLOCATE(CHARACTER(length) :: venue)
    FORALL (i = 1:length) venue(i:i) = venue_name(i)
  END SUBROUTINE Initialisation
  
  SUBROUTINE ToBeUsedElsewhere() BIND(C, NAME='ToBeUsedElsewhere')
    PRINT "('The name of the venue was ',A)", venue
  END SUBROUTINE ToBeUsedElsewhere
END MODULE m

#include <string>

// Fortran procedures.
extern "C" void Initialisation(const char *venue_name, int length);
extern "C" void ToBeUsedElsewhere();

int main()
{
  // The name of the venue is a little odd.
  std::string our_string = "Mary had a little lamb";
  
  // Call our Fortran procs.
  Initialisation(our_string.c_str(), our_string.size());
  
  ToBeUsedElsewhere();
  
  return 0;
}
>ifort /c /check:all /warn:all /standard-semantics "2015-09-19 string-f.f90"
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 16.0 Build 20150815
Copyright (C) 1985-2015 Intel Corporation.  All rights reserved.


>cl /W3 /EHsc "2015-09-19 string-c.cpp" "2015-09-19 string-f.obj"
Microsoft (R) C/C++ Optimizing Compiler Version 16.00.40219.01 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

2015-09-19 string-c.cpp
2015-09-19 string-c.cpp(13) : warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

"/out:2015-09-19 string-c.exe"
"2015-09-19 string-c.obj"
"2015-09-19 string-f.obj"

>"2015-09-19 string-c.exe"
The name of the venue was Mary had a little lamb

 

If the venue name is longer than what can fit in a C++ int, then Mary should consider playing elsewhere.

 

View solution in original post

0 Kudos
5 Replies
Arjen_Markus
Honored Contributor I
1,574 Views

When you do it like that, a hidden argument is passed to the Fortran routine (or at least assumed to be present by that routine).

The call at the C++ level should then be:

initialisation( venue_name, len(venu_name );

I would recommend using the ISO_C_BINDING module (untested code, just an illustration):

subroutine Initialisation(venue_name) bind(c, name = 'initialisation' )
    character(len=1), dimension(*), intent(in)  :: venue_name
	    
   !DEC$ ATTRIBUTES DLLEXPORT :: INITIALISATION
	    
   !How do I assign the string here?
   venue = venue_name
end subroutine Initialisation


This way no hidden argument is passed, you have control over the name of the routine as it is known on the C side (no decoration or case change for instance) and if you have several character arguments, you do not have to worry about the precise location of these hidden arguments.

0 Kudos
Dominic_C_1
Beginner
1,574 Views

Thanks!

Although I'm still having problems assigning the venue_name parameter to venue.

I'm not sure what type venue should be

I have tried

character(len=*) :: venue

character(len=10) :: venue

character(len=1) :: venue

 

I keep getting compile erroes of the type

error #6364: The upper bound shall not be omitted in the last dimension of a reference to an assumed size array.   [VENUE_NAME]

I honestly have no idea what this means.

 

 

 

0 Kudos
mecej4
Honored Contributor III
1,574 Views

You have kept us in the dark regarding what the call from the C code looks like, and how the arguments are declared there. Without that, there are too many combinations to cover when we speculate what goes wrong. Please show complete example code, including the Fortran and the C parts.

The very first line in your Fortran code in #1 is not valid unless the whole code is within a module, etc., because in Fortran you cannot declare global variables as in C. Therefore, you have to provide the relevant context.

Here is a working example. Of course, what you have in mind concerning what to do with the Fortran variable venue remains unknown.

File init.f90:

subroutine Initialisation(venue_name)
   character(len=10), intent(in)  :: venue_name

   character(len=10), save :: venue
   !DEC$ ATTRIBUTES DLLEXPORT :: INITIALISATION

   !How do I assign the string here?
   venue = venue_name

end subroutine Initialisation

File cmain.c:

#include <stdio.h>

extern void INITIALISATION(char *);

int main(){
char str[]="0123456789";
INITIALISATION(str);
}

 

0 Kudos
IanH
Honored Contributor II
1,575 Views
MODULE m
  IMPLICIT NONE
  CHARACTER(:), ALLOCATABLE :: venue
CONTAINS
  SUBROUTINE Initialisation(venue_name, length) BIND(C, NAME='Initialisation')
    USE ISO_C_BINDING, ONLY: C_CHAR, C_INT
    CHARACTER(KIND=C_CHAR), INTENT(IN) :: venue_name(*)
    INTEGER(C_INT), INTENT(IN), VALUE :: length
    INTEGER :: i
    ALLOCATE(CHARACTER(length) :: venue)
    FORALL (i = 1:length) venue(i:i) = venue_name(i)
  END SUBROUTINE Initialisation
  
  SUBROUTINE ToBeUsedElsewhere() BIND(C, NAME='ToBeUsedElsewhere')
    PRINT "('The name of the venue was ',A)", venue
  END SUBROUTINE ToBeUsedElsewhere
END MODULE m

#include <string>

// Fortran procedures.
extern "C" void Initialisation(const char *venue_name, int length);
extern "C" void ToBeUsedElsewhere();

int main()
{
  // The name of the venue is a little odd.
  std::string our_string = "Mary had a little lamb";
  
  // Call our Fortran procs.
  Initialisation(our_string.c_str(), our_string.size());
  
  ToBeUsedElsewhere();
  
  return 0;
}
>ifort /c /check:all /warn:all /standard-semantics "2015-09-19 string-f.f90"
Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 16.0 Build 20150815
Copyright (C) 1985-2015 Intel Corporation.  All rights reserved.


>cl /W3 /EHsc "2015-09-19 string-c.cpp" "2015-09-19 string-f.obj"
Microsoft (R) C/C++ Optimizing Compiler Version 16.00.40219.01 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

2015-09-19 string-c.cpp
2015-09-19 string-c.cpp(13) : warning C4267: 'argument' : conversion from 'size_t' to 'int', possible loss of data
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

"/out:2015-09-19 string-c.exe"
"2015-09-19 string-c.obj"
"2015-09-19 string-f.obj"

>"2015-09-19 string-c.exe"
The name of the venue was Mary had a little lamb

 

If the venue name is longer than what can fit in a C++ int, then Mary should consider playing elsewhere.

 

0 Kudos
Dominic_C_1
Beginner
1,574 Views

This worked perfectly, thank you.

0 Kudos
Reply