- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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"
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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); }
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This worked perfectly, thank you.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page