- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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);
}
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!
Link Copied
3 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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:
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]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
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.

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page