Home > Archive > Fortran > November 2005 > Fortran derived type and C struct passing character
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Fortran derived type and C struct passing character
|
|
| Brian McKenna 2005-11-18, 7:01 pm |
| I'm attempting to call a C function from Fortran where the argument is
a derived type in the Fortran and a GNU defined struct (struct tm in
time.h) in the C program.
The last variable within the struct tm is a const char *tm_zone in C,
and I have it defined as a CHARACTER, POINTER :: TM_ZONE in the Fortran
subroutine (see below). I am able to get all variables who's values
are obtained in the C passed back to Fortran via the struct/derived
type, however, I'm unable to get Fortran to find the length of the
character pointer passed back, I'm only getting the single first
character.
I understand and have gotten examples to work where a character is
passed between C and Fortran where the size of the C character pointer
must be sent as an additional argument back to Fortran, however, I
can't come up with a way to do this within the struct/derived type
being passed.
Does anyone know a way to pass a character value within a derived
type/struct between Fortran and C?
Aditionally, not that I'm too worried about this, the other problem is
more important, but I must fill a temporary struct tm in the C and
then set values in the struct tm passed in the arguments to the temp
values to get them passed. I'm guessing this is part of the GNU
localtime function possibly redeclaring memory for the variable?
Thanks for any suggestions or leads to solving this.
Brian
[Fortran code]
PROGRAM TIME
IMPLICIT NONE
INTEGER*4 :: TIME_T
TYPE TM
SEQUENCE
INTEGER*4 :: TM_SEC
INTEGER*4 :: TM_MIN
INTEGER*4 :: TM_HOUR
INTEGER*4 :: TM_MDAY
INTEGER*4 :: TM_MON
INTEGER*4 :: TM_YEAR
INTEGER*4 :: TM_WDAY
INTEGER*4 :: TM_YDAY
INTEGER*4 :: TM_ISDST
INTEGER*4 :: TM_GMTOFF
CHARACTER, POINTER :: TM_ZONE
END TYPE TM
TYPE( TM ) :: LOCTIME
TIME_T = 1119902400
CALL LOCALTIME( TIME_T, LOCTIME )
PRINT *, TIME_T
PRINT *, LOCTIME%TM_SEC
PRINT *, LOCTIME%TM_MIN
PRINT *, LOCTIME%TM_HOUR
PRINT *, LOCTIME%TM_MDAY
PRINT *, LOCTIME%TM_MON
PRINT *, LOCTIME%TM_YEAR
PRINT *, LOCTIME%TM_WDAY
PRINT *, LOCTIME%TM_YDAY
PRINT *, LOCTIME%TM_ISDST
PRINT *, LOCTIME%TM_GMTOFF
PRINT *, LOCTIME%TM_ZONE
END PROGRAM TIME
[C code]
#include <time.h>
void localtime_( time_t* curtime, struct tm *loctime2 ) {
struct tm *loctime;
/* Convert it to local time representation. */
loctime = localtime( curtime );
loctime2->tm_sec = loctime->tm_sec;
loctime2->tm_min = loctime->tm_min;
loctime2->tm_hour = loctime->tm_hour;
loctime2->tm_mday = loctime->tm_mday;
loctime2->tm_mon = loctime->tm_mon;
loctime2->tm_year = loctime->tm_year;
loctime2->tm_wday = loctime->tm_wday;
loctime2->tm_yday = loctime->tm_yday;
loctime2->tm_isdst = loctime->tm_isdst;
loctime2->tm_gmtoff = loctime->tm_gmtoff;
loctime2->tm_zone = loctime->tm_zone;
}
[Output]
1119902400
0
0
16
27
5
105
1
177
1
-14400
E
| |
| glen herrmannsfeldt 2005-11-19, 3:57 am |
| Brian McKenna wrote:
> I'm attempting to call a C function from Fortran where the argument is
> a derived type in the Fortran and a GNU defined struct (struct tm in
> time.h) in the C program.
> The last variable within the struct tm is a const char *tm_zone in C,
> and I have it defined as a CHARACTER, POINTER :: TM_ZONE in the Fortran
> subroutine (see below). I am able to get all variables who's values
> are obtained in the C passed back to Fortran via the struct/derived
> type, however, I'm unable to get Fortran to find the length of the
> character pointer passed back, I'm only getting the single first
> character.
While it would be legal for a C pointer to include some length
information, I know of no implementations that do that.
Fortran pointer variables include much more information, and so
are not compatible with C pointers in the way you are trying to
do it.
> I understand and have gotten examples to work where a character is
> passed between C and Fortran where the size of the C character pointer
> must be sent as an additional argument back to Fortran, however, I
> can't come up with a way to do this within the struct/derived type
> being passed.
If you really want to do that, I think you need a new struct defined
to match the Fortran derived type (they are actually called structures
in some parts of the standard). Then call a routine which can convert
to or from the C struct form, including any length information.
> Does anyone know a way to pass a character value within a derived
> type/struct between Fortran and C?
It might be that you use an INTEGER of the appropriate size in
Fortran, and somehow get/set the pointer (address) value.
> Aditionally, not that I'm too worried about this, the other problem is
> more important, but I must fill a temporary struct tm in the C and
> then set values in the struct tm passed in the arguments to the temp
> values to get them passed. I'm guessing this is part of the GNU
> localtime function possibly redeclaring memory for the variable?
Otherwise, if you have a Fortran 2003 compiler there is the C_PTR type
to use with C pointers, along with other types and functions needed to
process C pointers.
-- glen
| |
| Walter Spector 2005-11-19, 7:56 am |
| A possible alternative: If your compiler/library supports the POSIX PXF
bindings, you can simply call PXFLOCALTIME directly and not have to worry
about Fortran-C interfacing.
PXFLOCALTIME is called almost identically to its C counterpart. Pass it
the time-since-1970-in-seconds and it will pass back a 9 element array
with the desired values:
program localtime_test
implicit none
integer :: tis ! time in seconds since 1970
integer :: t(9)
integer :: pxferr
character(9) :: dow(0:6)
data dow /'sunday', 'monday', 'tuesday', 'wednesday', 'thursday',
& 'friday', 'saturday'/
! call pxftime (tis, pxferr)
tis = 1119902400
call pxflocaltime (tis, t, pxferr)
print '(3(a,i2.2))', ' time: ', t(3), ':', t(2), ':', t(1)
print '(2(a,i2.2),a,i4.4)', ' date: ', t(5), '/', t(4), '/', t(6)
print *, 'w day: ', dow(t(7))
print *, 'day of year: ', t(8)
if (t(9) == 1) then
print *, 'Daylight Savings Time'
else
print *, 'Standard Time'
end if
end program
Note that the values for month, year, and day of year are biased by 1, 1900, and 1
compared to the values you would get from the C struct.
When run with your value for the time, it prints:
$ a
time: 13:00:00
date: 06/27/2005
w day: monday
day of year: 178
Daylight Savings Time
Hope this helps,
Walt
| |
| David Frank 2005-11-19, 7:56 am |
| Jump at this opportunity to eliminate another troublesome C function..
integer :: time(8)
call date_and_time( values = time)
which provides 8 words of time info
|
|
|
|
|