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

Mixed C/Fortran, shared memory and common blocks...

steve_reussansys_com
1,471 Views
I have a c mainline that is calling fortran code. The fortran code has a common block that needs to be shared (to/with other applications). I'm doing this from within MS Visual Studio 2005, using the intel fortran plug-in.

I've successfully shared memory (using named file mappings) from the c mainline.
I've successfully implemented a structure in the mainline that is accessible within the fortran code.
I haven't been able to do both; i.e. define a global structure/common block that is also shared.

The lateset version of my C mainline is as follows:

typedef struct sd_type {
int number;
char text[256];
} sd_type ;

sd_type *pCFDATA ;


void main() {
extern void SOURCE1();
int size, ierr;
HANDLE hMemN ;
TCHAR handleLabel[] = TEXT("Global\\CFDATA2") ;

ierr = SUCCESS ;
size = sizeof(sd_type);
hMemN = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,size,handleLabel);
if (hMemN == NULL) ierr=FAIL;
if (ierr==SUCCESS) {
pCFDATA = MapViewOfFile(hMemN,FILE_MAP_ALL_ACCESS,0,0,size);
if (pCFDATA == NULL) {
CloseHandle(hMemN);
ierr=FAIL;
}
}

pCFDATA->number = 10 ;
sprintf(&(pCFDATA->text),"my text");

printf ("Hi\n");
printf ("CFDATA number=%d\n",pCFDATA->number);
printf ("CFDATA text=%s\n",pCFDATA->text);

SOURCE1();
printf ("CFDATA text=%s\n",pCFDATA->text);
}


The latest version of my fortran subroutine is as follows:

SUBROUTINE SOURCE1()

use iso_c_binding
INTEGER number
CHARACTER text*(256)
COMMON /pCFDATA/ number,text

WRITE (*,*) 'F number',number
WRITE (*,*) 'F text',text
text = 'new text'
END

The specific problem is that if I define the structure (rather than a pointer to the structure) in the mainline, then I can't use the createfilemapping call to share memory - but the structure is visible/accessible in the fortran code. Conversely, as the code above is written, if I define a pointer to the structure in the mainline, then I can allocate and share the structure's memory - but I can't figure out how to access the common block's data in fortran. The write statements seem to generate garbage, but if I hover my pointer over the structure label (i.e. pCFDATA) in the VS debugger, then I *can* see that the data is there. The debugger watch correctly shows "pCFDATA%number=10" and pCFDATA%text='my text'.

How do I access the contents of the common block in the write statements, using the rest of the code as it is?

Alternatively, is there a way to implement shared memory (for other apps) in the fortran code?

Thanks in advance!


0 Kudos
3 Replies
Steven_L_Intel1
Employee
1,471 Views
As you've discovered, you can't have it both ways. COMMON implies a specific layout in static memory, but you're doing dynamic allocation in C. Fortran does not have a direct equivalent of a C pointer but does have features to get what you want - just in a bit more convoluted fashion.

First, you need to declare an interoperable variable of type C_PTR, with the BIND(C) attribute. This must be in a module. This will overlay the C pointer.

Second, you need to declare a Fortran pointer of derived type matching the layout of the data.

Third, after the C code has allocated the data, you need to do a conversion of the C pointer to a Fortran pointer. Then your Fortran code can access the data through the Fortran pointer. Here's an overview of what it would look like:

[plain]module c_stuff
use iso_c_binding
implicit none

! Declare a variable that is the C pointer
type(C_PTR), bind(C,name="pCFDATA") :: pCFDATA

! Declare the structure of the data
type sd_type, bind(C)
  integer(C_INT) :: number
  character(256) :: text
end type sd_type

! Declare a Fortran pointer for the type
type(sd_type), pointer :: CFDATA

contains
! Routine to call once the C code has allocated the data
subroutine init
call C_F_POINTER (pCFDATA, CFDATA)
end subroutine init
end module c_stuff[/plain]

0 Kudos
steve_reussansys_com
1,471 Views
Hi Steve,

Many thanks for your recommendations; I now have the following (working) code:

MODULE C_STUFF
USE ISO_C_BINDING
IMPLICIT NONE

! Declare and overlay local version of c pointer
TYPE (C_PTR), BIND(C,NAME="pCFDATA") :: pCFDATA

! Declare the structure of data that pCFDATA points to
TYPE, BIND(C) :: sd_type
INTEGER (C_INT) :: number
CHARACTER(256) :: text
END TYPE SD_TYPE

! Declare Fortran pointer for the SD_TYPE data
TYPE(sd_type), POINTER :: CFDATA

CONTAINS
SUBROUTINE INIT
CALL C_F_POINTER(pCFDATA,CFDATA)
END SUBROUTINE INIT
END MODULE C_STUFF


SUBROUTINE SOURCE1()

USE C_STUFF

CALL INIT()

WRITE (*,*) 'F number',CFDATA%number
WRITE (*,*) 'F text',CFDATA%text

CFDATA%number = 20
CFDATA%text = 'changed'

END


I was struggling with figuring out what to put in the write commands, having first tried to process 'number' and 'text' as members of a common block. Is what I've done correct; i.e. what you'd had in mind?

The difficulty with the way the code is written above, is that the existing code base will simply refer to 'number' and/or 'text' since these are members of common blocks.

Is there any way to bind the c structure to a true fortran common block, or does this violate your original assertion that common blocks are incompatible with dynamically allocated c structures? If that is the case, then is my only option to replace all 'number' and 'text' references with the form included above?

TIA,
Steve
0 Kudos
Steven_L_Intel1
Employee
1,471 Views
Yes, that's what I had in mind. The COMMON can map to what C has put in static memory, which is just the pointer, and my suggested code matches that. Note that if you wanted to access the individual elements in C, you'd also have to use field notation, so this is not very different from Fortran.

I suppose what you could do is declare two more pointers, like this:

integer(C_INT), pointer :: number
character(256), pointer :: text

and then in the init routine, do this:

number => CFDATA%number
text => CFDATA%text

and then you could reference just number and text in the Fortran code.
0 Kudos
Reply