Fortran: How to store value 255 into one byte? - fortran

I would like to call a C api function from Fortran. The C function accepts an array of bytes:
void image(const void *bitmap, int w, int h);
where three successive bytes in *bitmap represent an RGB colour tripple and are interpreted as unsigned char in C. I want to initialize the bitmap in Fortran and take care of drawing inside C. Current definition in Fortran uses
integer*1 rgbImage(6,2)
to initialize an image of 2x2 for example, but compiler won't accept assignment
rgbImage(1,1) = 255
to get red colour. I've seen hints of using BYTE, UNSIGNED*1, LOGICAL*1 for unsigned single bytes, but gfortran (MacPort's gcc 4.4 or 4.6 under Mac OS X) isn't really happy with either of them. I could probably get away by cheating and assigning value -1 instead of 255, but that is very uncomfortable to use. The compiler flag -fno-range-check helped compile the code, but might not be available in other Fortran compilers and I consider it an ugly solution (I would still want to catch other warning). The values 'FF'X or '11111111'B are also recognized as 32-bit integers.
It is highly desirable for the code to be portable across different Fortran compilers.

My suggestion would be to use CHARACTER variables, and use ACHAR to set values (and ICHAR to convert back to integers as necessary). That should get you what you want and be completely portable. eg,
character, dimension(6,2) :: rgbImage
rgbImage(1,1) = achar(255)
Updated to add: if you're going to use the Fortran 2003 iso_c_binding stuff to interface to the C routines (highly recommended!) then you might as well make that rgbImage array characters of kind c_char, eg
character(kind=c_char), dimension(6,2) :: rgbImage
integer(kind=c_int) :: w, h
...
rgbImage(1,1) = achar(255)
...
call image(rgbImage, w, h)
where you've defined the interface for the routine
interface
subroutine image(img, w, h) bind(C)
use, intrinsic :: iso_c_binding
implicit none
integer(kind=c_int), intent(in), value :: w, h
character(kind=c_char) :: img(:,:)
end subroutine image
end interface

An alternative strategy that may be suitable for some circumstances is to pass the 1 byte c int array to an Integer(1) array, say, iVal(:), then create another Int array such as Integer(2) iVal2(:), then:
Where(iVal(:) < 0)
iVal2(:) = -iVal(:)+127
ElseWhere
iVal2(:) = iVal(:)
End Where
... this can be a bit more efficient/cleaner compared to converting to/fro chars (sometimes) and requires less coding (sometimes).
If you do a lot of this type of thing (interfacing various types of usigned's etc to Fortran), a few utility routines relying on Fortran's bit intrinsics may be a worthwhile investment (e.g. BTest(), iBSet() etc).

Related

How to store Fortran-style long character scalar in C++ data structure

I am working with a legacy Fortran library that requires a character scalar PATH as an argument to the subroutine. The original interface was:
SUBROUTINE MINIMAL(VAR1, ..., PATH)
CHARACTER (LEN=4096) PATH
...
I need to be able to call this from C++ so I have made the following changes:
SUBROUTINE MINIMAL(VAR1, ..., PATH) &
BIND (C, NAME="minimal_f")
USE ISO_C_BINDING, ONLY: C_CHAR, C_NULL_CHAR
CHARACTER (KIND=C_CHAR, LEN=1), DIMENSION(4096), INTENT(IN) :: PATH
CHARACTER (LEN=4096):: new_path
! Converting C char array to Fortran CHARACTER.
new_path = " "
loop_string: do i=1, 4096
if ( PATH (i) == c_null_char ) then
exit loop_string
else
new_path (i:i) = PATH (i)
end if
end do loop_string
as per this answer. This works to convert the C-style char array to its Fortran scalar equivalent, with two problems:
This code is on the critical path so doing the same conversion every time when the answer is the same is inefficient
I would strongly prefer to not have to edit legacy code
I have tried:
Just accepting a CHARACTER (LENGTH=4096) :: new_path directly with the ISO C binding, but I get the following compiler error:
Error: Character argument 'new_path' at (1) must be length 1 because procedure 'minimal' is BIND(C)
This answer and others that I have read suggest that the ISO C binding seems to restrict what I can pass as parameters to the function, although I haven't found any official documentation yet.
This answer, which gives another algorithm to turn a C-style string
into a Fortran-style equivalent in the C code and passing it to the Fortran subroutine without using the ISO C binding. (This function suggests a similar algorithm). This seems like exactly what I want but I have a linker error without the binding:
Undefined symbols for architecture x86_64:
"_minimal", referenced from:
C++-side function declaration:
extern "C" {
double minimal(int* var1, ..., const char* path);
}
This suggests that my compiler (gcc) prepends the function name with an underscore when in an extern block. gfortran, however, does not let me name the subroutine _minimal so the linker can't find the symbol _minimal. (The aforementioned link suggests adding an underscore to the end of the C-side function name but this doesn't work either because of the leading underscore.)
I want to process a C-style string into a Fortran-style character scalar once in my C++ code and be able to pass it into the original interface. Any ideas?
Fortran 2018 allows interoperable procedures to have character dummy arguments of assumed length, relaxing the restriction that such dummy arguments must be of length one.
So we can write a Fortran procedure as
subroutine minimal(path) bind(c)
use, intrinsic :: iso_c_binding, only : c_char
character(*,c_char), intent(in) :: path
...
end subroutine minimal
and continue our life knowing that we've also improved our Fortran code by using an assumed length scalar instead of an explicit length one. No "Fortran side" copy of this character dummy is required.
The sad part of this story is that the dummy argument path is not interoperable with a char. So instead of the formal parameter of the C (or C++) function being char * , it must be CFI_cdesc_t *. For (C) example:
#include "ISO_Fortran_binding.h"
#include "string.h"
void minimal(CFI_cdesc_t *);
int main(int argc, char *argv[]) {
/* Fortran argument will be a scalar (rank 0) */
CFI_CDESC_T(0) fpath;
CFI_rank_t rank = 0;
char path[46] = "afile.txt";
CFI_establish((CFI_cdesc_t *)&fpath, path, CFI_attribute_other,
CFI_type_char, strlen(path)*sizeof(char), rank, NULL);
minimal((CFI_cdesc_t *)&fpath);
return 0;
}
A C++ example will be similar.
An notable part of the story is that you'll need a Fortran compiler which implements this part of Fortran 2018. GCC 11 does not.
IanH's answer draws attention to an approach which avoids modifying the original Fortran subroutine at all. There certainly are times when avoiding any change there is good (repeating slightly what IanH said):
using bind(c) means an explicit interface will now always be required when calling the modified subroutine through Fortran itself. Perhaps some parts of your code used it with an implicit interface
the original was tested (or wasn't) and you don't want to break anything
you don't want to potentially change the argument from default kind to interoperable kind (if these do differ)
the explicit length dummy argument really is wanted
you just don't want to modify it if not required
Any one of those would make a good argument, so in that spirit I'll add to the C example with the thin wrapper.
Fortran:
subroutine minimal_wrap(path) bind(c, name='minimal')
use, intrinsic :: iso_c_binding, only : c_char
character(*,c_char), intent(in) :: path
call minimal(path)
end subroutine minimal_wrap
subroutine minimal(path)
character(4096) path
print*, trim(path)
end subroutine minimal
C:
#include "ISO_Fortran_binding.h"
#include "string.h"
void minimal(CFI_cdesc_t *);
static const int pathlength=4096;
int main(int argc, char *argv[]) {
/* Fortran argument will be a scalar (rank 0) */
CFI_CDESC_T(0) fpath;
CFI_rank_t rank = 0;
char path[pathlength];
/* Set path as desired. Recall that it shouldn't be null-terminated
for Fortran */
CFI_establish((CFI_cdesc_t *)&fpath, path, CFI_attribute_other,
CFI_type_char, pathlength*sizeof(char), rank, NULL);
minimal((CFI_cdesc_t *)&fpath);
return 0;
}
C++ using containers will arguably be nicer.
Recall that this puts responsibility on the C side to ensure the array is long enough (as you have in pure Fortran calls).
Equally if you need to be robust to differences in default character and interoperable character with that copy (as in IanH's answer) you can apply those same tricks to copy as required (or you can do this with conditional compilation and configure-time checks). By this point however, you may as well just assume always copy or use the array argument.
The answer to the question title is typically a std::string object, padded to the relevant fixed Fortran CHARACTER scalar length with spaces. Alternative storage objects (std::vector<char>, or a C-style char array) could be used on the C++ side, but the approach is similar.
(If the Fortran code used an assumed length character argument, rather than fixed length, then the padding would not be required. Whether this change is possible depends on the details of the MINIMAL subroutine. Fixed length character variables are typically an anachronism - this answer is not advocating their use in new code.)
On the Fortran side, you can write a thin wrapper that the C++ can call, that uses sequence and pointer association to avoid the need to copy the string data, for typical C++/Fortran platforms of today. A copy (or modification of the legacy Fortran code) is unavoidable if the interoperable character kind is not the same as the character kind of the legacy Fortran procedure. The example code below is robust to this situation, but I expect platforms that require that code path to be rare.
For default character and C_CHAR interoperable character arguments, sequence association permits an array dummy argument to be associated with the sequence of characters designated by the actual argument. This effectively permits association between character scalars and arrays with different lengths.
(Do not confuse the ISO_C_BINDING intrinsic module with the BIND(C) procedure suffix. BIND(C) fundamentally changes the interface of a procedure to enable calls between C and Fortran - ISO_C_BINDING is just a module with some handy types, constants and procedures for such calls.)
Example C++:
#include <string>
#include <cassert>
const int path_length = 4096;
extern "C" int legacy_cintf(char* array);
int main()
{
std::string some_long_text
= "It was the best of times, it was the worst of times, it was "
"the age of wisdom, it was the age of foolishness, it was the "
"epoch of belief, it was the epoch of incredulity, it was the "
"season of light, it was the season of darkness, it was the "
"spring of hope, it was the winter of despair.";
assert(some_long_text.size() < path_length);
std::string path = std::string(path_length, ' ');
path.replace(0, some_long_text.size(), some_long_text);
legacy_cintf(&path[0]);
return 0;
}
Example Fortran:
MODULE m
IMPLICIT NONE
CONTAINS
SUBROUTINE legacy_cintf(array) BIND(C, NAME='legacy_cintf')
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_CHAR
CHARACTER(LEN=1,KIND=C_CHAR), TARGET :: array(4096)
CHARACTER(LEN=SIZE(array)), POINTER :: scalar
LOGICAL :: copy_required
copy_required = C_CHAR /= KIND(scalar)
IF (copy_required) THEN
ALLOCATE(scalar)
CALL do_copy(array, scalar)
ELSE
CALL do_associate(array, scalar)
END IF
CALL LEGACY(scalar)
IF (copy_required) DEALLOCATE(scalar)
END SUBROUTINE legacy_cintf
SUBROUTINE do_associate(arg, scalar)
CHARACTER(*), INTENT(OUT), POINTER :: scalar
CHARACTER(LEN=LEN(scalar)), INTENT(IN), TARGET :: arg(1)
scalar => arg(1)
END SUBROUTINE
SUBROUTINE do_copy(arg, scalar)
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_CHAR
CHARACTER(*), INTENT(OUT) :: scalar
CHARACTER(LEN=LEN(scalar), KIND=C_CHAR), INTENT(IN) :: arg(1)
scalar = arg(1)
END SUBROUTINE do_copy
END MODULE m
SUBROUTINE LEGACY(PATH)
CHARACTER(4096) :: PATH
PRINT *, TRIM(PATH)
END SUBROUTINE LEGACY

Fortran reinterpret_cast Equivalent

I have some functions written in Fortran that take a structure as an argument, but the caller has the data stored in an INTEGER*4(2) array. In order to avoid the copy between the two data structures, I'm wondering if the following implementation of a C++-like reinterpret_cast is valid according to the specification:
STRUCTURE /TimeStamp/
INTEGER*4 secondsSinceEpoch
INTEGER*4 nanos
END STRUCTURE
STRUCTURE /reinterpret_cast/
UNION
MAP
INTEGER*4, POINTER :: array(:)
END MAP
MAP
TYPE (TimeStamp), POINTER :: tstamp
END MAP
END UNION
END STRUCTURE
SUBROUTINE set_time(timeArg)
INTEGER*4, TARGET :: timeArg(2)
RECORD /reinterpret_cast/ time
time % array => timeArg
time % tstamp % secondsSinceEpoch = 12
time % tstamp % nanos = 0
END
Is this implementation of the set_time method guaranteed to work (e.g., set the values of timeArg(1) and timeArg(2))?
No, your function is not guaranteed to work by the Fortran standard and many compilers will refuse the syntax altogether. I am not sure whether Fortran pointers are allowed in the DEC structures and if yes, whether you can union them. They (structure and union and record) were designed before Fortran pointers were put into the standard and are strongly discouraged for new code, but it is quite possible Intel allowed Fortran pointers in allowed them.
Much easier (at least for me) way is to use Fortran standard type(c_ptr) which is basically the C void * pointer.
SUBROUTINE set_time(timeArg)
USE, INTRINSIC :: ISO_C_BINDING
INTEGER(c_int_32), TARGET :: timeArg(2)
type(TimeStamp), POINTER :: tstamp
CALL c_f_pointer(c_loc(timeArg), tstamp)
tstamp % secondsSinceEpoch = 12
tstamp % nanos = 0
END
I also changed the INTEGER*4 because it is also not standard conforming and not guaranteed to be C-interoperable.
Do note that the address of the target dummy argument is valid only in the subroutine unless the actual argument is pointer or target.
What you are looking for is the F90-standard function TRANSFER. It interprets the bit representation of the operand as if it was of the same type of another variable (the "mold"). Thus, this:
USE ISO_FORTRAN_ENV ! For the REALnn and INTnn constants
REAL(REAL32) r
INTEGER(INT32) i
r = 1.0
i = TRANSFER(r, i) ! The second "i" here is unevaluated, just gives the type
Is equivalent to this:
float r = 1.0;
int32_t i;
i = *reinterpret_cast<int*>(&f);
Note that the REALnn and INTnn constants are from Fortran 2008, so your compiler might not have them. I just used them as examples to make sure that the types were compatible, since just like in C, the standard does not say precisely how big a "default real" or "default integer" are.
As an example, I frequently use this function when creating Fortran-based MEX functions in Matlab, since the Matlab interface with Fortran is based on F77 and does not allow you to use pointers to Matlab memory directly, unlike the C interface. I use the TRANSFER function and the ISO_C_BINDING module (F2003) to cast the "integer" (actually a C pointer) Matlab gives me to the Fortran type C_PTR, to a Fortran pointer. Like this:
USE ISO_C_BINDING ! For C_PTR and related functions
INTEGER(INT32), POINTER :: arrayPtr(:)
mwSize n ! This is a type defined in the Matlab-Fortran interface
mwPointer myMatlabArray = ... ! So is this
TYPE(C_PTR) cPtrToData
! Cast the returned C pointer to the data (Matlab interface returns an integer type)
cPtrToData = TRANSFER(mxGetData(myMatlabArray), cPtrToData)
! Since Fortran arrays/pointers have size information, get the length
n = mxGetNumberOfElements(myMatlabArray)
CALL C_F_PTR(cPtrToData, arrayPtr, [n]) ! Associate the Fortran ptr
array(3:7) = ... ! Do whatever, no need to copy
Which is the rough equivalent to the C version:
mxArray* myMatlabArray = ...; //
mwSize n = mxGetNumberOfElements(myMatlabArray);
int* arrayPtr = (int*)mxGetData(myMatlabArray);
array[3] = ... // Do whatever, no need to copy
So in both cases these MEX functions could be called with Matlab array of Matlab type int32.

Compiling fortran and C++ program and linking from intel compiler

I have a Fortran main program under which there are many subroutines. One of the subroutine calls a c++ function. That c++ function is calling another Fortran subroutine. Now I need to compile all of them together to get the output.
I have tried to compile c++ file with icl. Then I have used ifort as a linker between Fortran file and object file created for the c++. But the method is not working. Its showing unresolved external symbol.
I expect that you at least saw this: https://software.intel.com/en-us/node/691954
What they wrote there mostly refers to C, though there is mention of C++ libraries. IF you link with C++ ocde, you need those.
You should read about symbol name mangling in C++. Because C++ supports overloaded funktions but linker requires unique symbols, C++ generates
something like _foo****#8 instead of foo for a function foo(int i, float j), where * depend on compiler and on type of arguments.
Fortran code generates C-styled symbols if BIND(C) used, you can force C++ to generate one for a function , by using extern "C" in C++ code both for prototypes of fortran functions called from C++ and for functions that will be called from fortran.
This example works with C compiler, but for C++ you need to change symbol generated (https://software.intel.com/en-us/node/691929#92BDCE7A-30FA-4A60-BCDB-7CE1521572EC). Note that C and Fortran interoperability isn't standardized and usually not portable from one compiler set to another. I had to deal with problem that Compaq compiler was mangling function names as well but not in C++ way, or that PGI Fortran required stdcall conventions.
Fortran Code Example
subroutine Simulation(alpha, beta, gamma, delta, arrays) BIND(C)
use, intrinsic :: ISO_C_BINDING
implicit none
integer (C_LONG), value :: alpha
real (C_DOUBLE), intent(inout) :: beta
integer (C_LONG), intent(out) :: gamma
real (C_DOUBLE),dimension(*),intent(in) :: delta
type, BIND(C) :: pass
integer (C_INT) :: lenc, lenf
type (C_PTR) :: c, f
end type pass
type (pass), intent(inout) :: arrays
real (C_FLOAT), ALLOCATABLE, target, save :: eta(:)
real (C_FLOAT), pointer :: c_array(:)
...
! Associate c_array with an array allocated in C
call C_F_POINTER (arrays%c, c_array, (/arrays%lenc/) )
...
! Allocate an array and make it available in C
arrays%lenf = 100
ALLOCATE (eta(arrays%lenf))
arrays%f = c_loc(eta)
...
end subroutine Simulation
C Struct declaration Example
struct pass {int lenc, lenf; float *c, *f;};
C Function Prototype Example
void simulation(long alpha, double *beta,
long *gamma, double delta[], struct pass *arrays);
C Calling sequence Example
simulation(alpha, &beta, &gamma, delta, &arrays);

Function type does not match the function definition

I am new to Fortran, writing some practice code with a function that returns Farenheit from Celsius
program Console1
implicit none
real, parameter :: ikind = selected_real_kind(p=15)
real (kind = ikind):: c,f,o,faren
print *, "enter a temperature in degrees celsius"
read *, c
write(*,10) "farenheit =", faren(c)
10 format(a,f10.8)
end program Console1
function faren(c)
real, parameter :: ikind = selected_real_kind(p=15)
real (kind = ikind):: c,f
faren = (9/5)*c + 32
end function faren
I get an error #7977 : The type of the function reference does not match the type of the function definition.
So with that if i change function faren(c) to real function faren(c)
I get the same error, but the types are the same?
Am i missing something? Do I have to define the function in the main program?
There are several issues in addition to the structural/code arrangement ones already noted.
First, KIND is an integer, so you want to change
real, parameter :: ikind = selected_real_kind(p=15)
to
integer, parameter :: ikind = selected_real_kind(p=15)
Ideally, you want to define that in only one place (i.e. in a module) and reference it from both your main program and the function, but the code should be fine as it is for test purposes.
A second issue that often trips up newcomers to Fortran (and Python2) is that real numbers and integers are distinct types and are not generally interchangeable.
faren = (9/5)*c + 32
simplifies to
faren = (1)*c + 32
because integer division has an integer result; 9/5 = 1
Fortran is picky about numerical values (that's sort of the whole point of the language) so what you probably want is:
faren = (9.0 / 5.0) * c + 32.0
Or more precisely, if faren is defined with a specific precision of ikind,
faren = (real(9.0,ikind) / real_(5.0,ikind)) * c + real(32.0,ikind)
or
faren = (9.0_ikind / 5.0_ikind) * c + 32.0_ikind
This syntax tends to make people's heads explode. Welcome to modern fortran ;)
The last issue deals with the horrors of Fortran I/O. From a design standpoint, you need to know what results the user expects and make sure the output format can display them. The legitimate range of input values for c is -273.15 (give or take) to some upper bound which relies on the use case for the code. If you're dealing with cooking temperatures, you probably won't exceed 400.0; if you're doing fusion research, you could be going much higher. Are 8 figures past the decimal useful or believable? In this case, we're just testing the code so we may not need a lot of precision in the output; you'll want to change the output format to something like:
10 format(a,es10.2)
or
10 format(a,g16.8)
You need to ensure the total field width (the number before the dot) can contain the decimal part (the number after the dot) along with the integer part of the number, plus the space needed to show sign and exponent. For scientific notation, four characters are eaten by mantissa sign, decimal point, 'E' and exponent sign. It may be safer just starting out to use an output format of *; it's frustrating to fight with numerics and formatting simultaneously.
That is a good effort and simple start to work through the nuance, so a good question.
Personally I would use reals for the math, rather the 9/5, and use a module. In this example you could pass in a real or a double to C2Faren and the interface/procedure will sort out whether to use the real or the double version. Then you have a few options in case you want different precision.
You could also use the ISO_C_BINDING if you do mixed language...
MODULE MyTEMPS
PRIVATE
DOUBLE PRECISION, PARAMETER :: C2F_ScaleFact = 1.8D0
DOUBLE PRECISION, PARAMETER :: F2C_ScaleFact = /(1.0D0 / 1.8D0)/
DOUBLE PRECISION, PARAMETER :: F2C_Offset = 32.0D0
PUBLIC Faren2C
INTERFACE C2Faren
MODULE PROCEDURE C2Faren_Real, C2Faren_DBL
END INTERFACE
CONTAINS
!========= REAL VERISON =========
REAL FUNCTION C2Faren_Real(c)
IMPLICIT NONE
real, INTENT(IN ) :: c
C2Faren_Real = ( C*F2C_ScaleFact ) + F2C_Offset
RETURN
END FUNCTION C2Faren_Real
!========= DOUBLE VERSION =========
DOUBLE PRECISION FUNCTION C2Faren_DBL(c)
IMPLICIT NONE
DOUBLE PRECISION , INTENT(IN ) :: c
C2Faren_DBL = ( C*F2C_ScaleFact ) + F2C_Offset
RETURN
END FUNCTION C2Faren_DBL
!========= REAL VERSION (Faren to Centigrade) =========
REAL FUNCTION faren2C(Faren)
IMPLICIT NONE
REAL, INTENT(IN ) :: Faren
faren2C = (faren - F2C_Offset) / F2C_ScaleFact
RETURN
END FUNCTION faren2C
END MODULE MyTEMPS
Then your program uses the module via USE n the second line...
program Console1
USE MyTEMPS !<== Here
implicit none
real :: c, f
DOUBLE PRECISION :: Dc, Df ! No way to get Df to C or DC in the module (yet)!
print *, "enter a temperature in degrees celsius"
read *, c
write(*,10) "farenheit =", C2faren(c)
10 format(a,f10.6)
Dc = C
write(*,12) "farenheit =", C2faren(Dc)
12 format("DBL:",A,f10.6)
F = Dc
write(*,14) "Centigrade =", faren2C(F)
14 format("DBL:",A,f10.6)
end program Console1
So/and the main advantage of the module is when you end up wanting to use this stuff in a variety of programs and test and sort out the module once... Usually people put this sort of stuff (lots of modules) in a library, when the module(s) have lot of functions.
You could also put just the real, parameter :: ikind = selected_real_kind(p=15) into a module and use that in both the program and the function and you would be there. You were real close, and it mostly a matter of style and utility.
For Intel Fortran you can use REAL(KIND=4) and REAL(KIND=8)... Which I do, but that is not portable to gfortran, so it is probably a better habit to use the ISO_C_BINDING or just use REAL and DOUBLE PRECISION.
Modules are great but if you have a very simple code another way to work is to put the subroutines and functions in your main program. The trick is to put them after the word contains:
program xxx
stuff
contains
subroutine yyy
function zzz
end program xxx
In this way the functions can see into the contents of the main program so you don't have to re-declare your parameters and you are likely to get more meaningful error messages.
Since you are new I have a great resource I learned a lot from to share:
http://www.uv.es/dogarcar/man/IntrFortran90.pdf

Allocating memory in C for a Fortran allocatable

We are trying to take over the memory allocation of a legacy Fortran code (+100,000 lines of code) in C++, because we are using a C library for partitioning and allocating distributed memory on a cluster. The allocatable variables are defined in modules. When we call subroutines that use these modules the index seems to be wrong (shifted by one). However, if we pass the same argument to another subroutine we get what we expect. The following simple example illustrates the issue:
hello.f95:
MODULE MYMOD
IMPLICIT NONE
INTEGER, ALLOCATABLE, DIMENSION(:) :: A
SAVE
END MODULE
SUBROUTINE TEST(A)
IMPLICIT NONE
INTEGER A(*)
PRINT *,"A(1): ",A(1)
PRINT *,"A(2): ",A(2)
END
SUBROUTINE HELLO()
USE MYMOD
IMPLICIT NONE
PRINT *,"A(1): ",A(1)
PRINT *,"A(2): ",A(2)
CALL TEST(A)
end SUBROUTINE HELLO
main.cpp
extern "C" int* __mymod_MOD_a; // Name depends on compiler
extern "C" void hello_(); // Name depends on compiler
int main(int args, char** argv)
{
__mymod_MOD_a = new int[10];
for(int i=0; i<10; ++i) __mymod_MOD_a[i] = i;
hello_();
return 0;
}
We are compiling with:
gfortran -c hello.f95; c++ -c main.cpp; c++ main.o hello.o -o main -lgfortran;
Output from running ./main is
A(1): 1
A(2): 2
A(1): 0
A(2): 1
As you can see the output of A is different, though both subroutines printed A(1) and A(2). Thus, it seems that HELLO starts from A(0) and not A(1). This is probably due to that ALLOCATE has never been called directly in Fortran so that it is not aware of the bounds of A. Any work arounds?
The ISO_C_BINDING "equivalent" code:
c++ code:
extern "C" int size;
extern "C" int* c_a;
extern "C" void hello();
int main(int args, char** argv)
{
size = 10;
c_a = new int[size];
for(int i=0; i<size; ++i) c_a[i] = i;
hello();
return 0;
}
fortran code:
MODULE MYMOD
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
INTEGER, BIND(C) :: SIZE
TYPE (C_PTR), BIND(C) :: C_A
INTEGER(C_INT), POINTER :: A(:)
SAVE
END MODULE
SUBROUTINE TEST(A)
IMPLICIT NONE
INTEGER A(*)
PRINT *,"A(1): ",A(1)
PRINT *,"A(2): ",A(2)
END
SUBROUTINE HELLO() BIND(C)
USE, INTRINSIC :: ISO_C_BINDING
USE MYMOD
IMPLICIT NONE
CALL C_F_POINTER(C_A,A,(/SIZE/))
PRINT *,"A(1): ",A(1)
PRINT *,"A(2): ",A(2)
CALL TEST(A)
END SUBROUTINE
Output:
A(1): 0
A(2): 1
A(1): 0
A(2): 1
Fortran array dummy arguments always start at the lower bound defined in the subroutine. Their lower bound is not retained during the call. Therefore the argument A in TEST() will always start at one. If you wish it to start from 42, you must do:
INTEGER A(42:*)
Regarding the allocation, you are playing with fire. It is much better to use Fortran pointers for this.
integer, pointer :: A(:)
You can then set the array to point to a C buffer by
use iso_c_binding
call c_f_pointer(c_ptr, a, [the dimensions of the array])
where c_ptr is of type(c_ptr), interoperable with void *, which also comes from iso_c_binding.
---Edit---
Once I see that #Max la Cour Christensen implemented what I sketched above, I see I misunderstood the output of your code. The descriptor was indeed wrong, though I didn't write anything plain wrong. The solution above still applies.
The internal representation of fortran arrays is very different than the one used in C/C++.
Fortran uses descriptors that start with a pointer to the array data, and followed by element type size, number of dimensions, some padding bytes, an internal 32/64 bit byte sequence indicating various flags such as pointer, target, allocatable, can be deallocated, etc. Most of these flags are not documented (at least in ifort that I have worked with), and at the end is a sequence of records, each describing the number of elements in the corresponding dimension, distance between elements, etc.
To 'see' an externally created array from fortran, you'd need to create such descriptors in C/C++, but, it does not end there because fortran also makes copies of them in the startup code of each subroutine before it gets to the first one of your statements, depending on indicators like 'in', 'out, 'inout', and other indicators used in the fortran array declaration.
Arrays within a type declared with specific sizes map well (again in ifort) to corresponding C struct members of the same type and number of elements, but pointer and allocatable type members are really descriptors in the type that need to be initialized to the correct values in all their fields so fortran can 'see' the allocatable value. This is at best tricky and dangerous, since the fortran compiler may generate copy code for arrays in undocumented ways for optimization purposes, but it needs to 'see' all the involved fortran code to do so. Anything coming outise of the fortran domain, is not known and can result in unexpected behavior.
Your best bet is to see if gfortran supports something like iso_c_binding and define such interfaces for your fortran code, and then use iso_c_binding intrinsics to map the C_PTR pointers to fortran pointers to types, arrays, etc.
You can also pass a pointer to a one-dimensional array of char, and its size, and this works for strings mostly as long as the size is passed by value as last argument (again, compiler and compiler-flag dependent).
Hope this helps.
EDIT: changed 'ifort's iso_c_binding' to 'iso_c_binding after Vladimir's comment - thanks!