For Programmers: Free Programming Magazines  


Home > Archive > Fortran > August 2005 > portable 'sizeof' solution









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 portable 'sizeof' solution
guilhem.bonnefille@c-s.fr

2005-08-09, 4:04 am

In order to make a Fortran90 / C generic interface, I have to compute
the size of a Fortran90 variable in order to memcpy it in C (in both
directions, F90->C, C->F90).

My code, must work with different compilers (f90, pgf90, g95...) on
different platform (SUN, HP-UX, Linux).
I found that the 'sizeof' directive is not as portable as the C one
(some compilers do not support it).

What can I do?
Any solution is good: I can write and compile code on the fly, the main
goal is to find the size of a type (I read the Fortran90 declaration in
a file, and I extract the type part) in order to memcpy it.

Arjen Markus

2005-08-09, 4:04 am

Try the following code:

character(len=1) :: a_single_byte
type(MY_OWN_TYPE) :: my_struct
sizeof = len( transfer( my_struct, a_single_byte ) )

Note, I have not tested this, but the TRANSFER() function
can do miracles (well, black magic might be a better word)

Regards,

Arjen

Michel OLAGNON

2005-08-09, 4:04 am



guilhem.bonnefille@c-s.fr wrote:
> In order to make a Fortran90 / C generic interface, I have to compute
> the size of a Fortran90 variable in order to memcpy it in C (in both
> directions, F90->C, C->F90).
>
> My code, must work with different compilers (f90, pgf90, g95...) on
> different platform (SUN, HP-UX, Linux).
> I found that the 'sizeof' directive is not as portable as the C one
> (some compilers do not support it).
>
> What can I do?
> Any solution is good: I can write and compile code on the fly, the main
> goal is to find the size of a type (I read the Fortran90 declaration in
> a file, and I extract the type part) in order to memcpy it.
>


inquire (iolength= ...) should work in most cases.

Michel

David Flower

2005-08-09, 9:03 am


guilhem.bonnefille@c-s.fr wrote:
> In order to make a Fortran90 / C generic interface, I have to compute
> the size of a Fortran90 variable in order to memcpy it in C (in both
> directions, F90->C, C->F90).
>
> My code, must work with different compilers (f90, pgf90, g95...) on
> different platform (SUN, HP-UX, Linux).
> I found that the 'sizeof' directive is not as portable as the C one
> (some compilers do not support it).
>
> What can I do?
> Any solution is good: I can write and compile code on the fly, the main
> goal is to find the size of a type (I read the Fortran90 declaration in
> a file, and I extract the type part) in order to memcpy it.


How about :

<your type> X(2)
INTEGER*1 I(33), L
DATA I /0, 1, 2, etc. 31, 32/
EQUIVALENCE ( X, I )
EQUIVALENCE ( L, X(2) )

L should now contain the required value; note that this should work
under any version of FORTRAN that supports an integer*1 (or BYTE) type.

David Frank

2005-08-09, 9:03 am


"Michel OLAGNON" <molagnon@ifremer-a-oter.fr> wrote in message
news:42F87031.40706@ifremer-a-oter.fr...[color=darkred]
>
>
> guilhem.bonnefille@c-s.fr wrote:

Start a petition for those J3 members voting AGAINST adding SIZEOF to F2003
to resign.

BTW, the 3 solutions posted so far suck!!

1. IMO, even JVB wont be able to make transfer do this
2. IOLENGTH doesnt calculate size in bytes, CVF SIZEOF does.
3. Assumes byte array size is 33

Below is less nasty, but at least works
program get_sizeof
type mytype
character :: c
character(10) :: s
real :: x
end type
type (mytype) dat(2)

write (*,*) loc(dat(2))-loc(dat(1)) ! CVF outputs 16 (padded to word
bound)

! or write (*,*) c_loc(dat(2)-c_loc(dat(1)) using standard fortran

end program


David Frank

2005-08-09, 9:03 am


"Arjen Markus" <arjen.markus@wldelft.nl> wrote in message
news:1123577464.635793.212080@f14g2000cwb.googlegroups.com...
> Try the following code:
>
> character(len=1) :: a_single_byte
> type(MY_OWN_TYPE) :: my_struct
> sizeof = len( transfer( my_struct, a_single_byte ) )
>
> Note, I have not tested this, but the TRANSFER() function
> can do miracles (well, black magic might be a better word)
>
> Regards,
>
> Arjen
>


Arjen,
elsewhere I say your idea above wont work, but after 2nd thought, I found
your version can be fixed
(just trying to beat JVB to it).. Yes, transfer is a magical function.

! ------------------
program get_sizeof
type mytype
character :: c
character(10) :: s
real :: x
end type
type (mytype) dat
integer(1) :: idat(9999)

write (*,*) size(transfer(dat,idat)) ! outputs 16
end program


Arjen Markus

2005-08-09, 9:03 am

Hm, it won't work with a character? Okay, the above seems a good way
around it ...

That does not mean to say that TRANSFER() should _not_ put awe into a
novice's heart!

Regards,

Arjen

Richard E Maine

2005-08-09, 5:03 pm

In article <1123574738.781282.61260@f14g2000cwb.googlegroups.com>,
guilhem.bonnefille@c-s.fr wrote:

> In order to make a Fortran90 / C generic interface, I have to compute
> the size of a Fortran90 variable in order to memcpy it in C (in both
> directions, F90->C, C->F90).


Very familiar problem. I tried to squeeze an intrinsic for this purpose
into f2003, but I was too late and it didn't get accepted. It is being
actively pursued for the standard after f2003. But that's a bit of a
wait (since f2003 compilers aren't even here yet).

My summary of the current hacks available follows, though I might have
forgotten about some trick. None of these are clean and perfect. That's
why I've advocated for the intrinsic to be added. I mention some of the
potential problems below. DO note however, that many of the problems are
just potential. In practice, any of these will usually work in most
situations.

I'm not going to try to show actual code (I'd probably screw it up if I
tried without testing, as all of these can be a bit tricky).

1. SIZE(TRANSFER(...)) can certainly be made to do the trick. Note that
size() is a standard f90 intrinsic, unlike sizeof(). Size gives you the
number of elements in an array. So you can use TRANSFER to an array of
some one-byte type and find the size of the resulting array. When I did
this, I used to use a 1-byte integer kind specified using
selected_integer_kind. I think pretty much all the compilers now support
a one-byte kind, though in the past I have run into ones that didn't.
You can use an array of default character*1 if desparate; they aren't
actually guaranteed to be one byte, but (almost?) always are. I haven't
actually seen an exception, though that might be because I haven't
worked with Japanese compilers. Unicode might someday change this also.
There used to be compilers that would crash on constructs like this, but
I think that has improved in the last decade or so....after I swore off
using TRANSFER for much of anything myself.

2. inquire(iolength=...) can also be made to work. But it has caveats
based on the fact that this isn't really its purpose. First, the units
of the result are processor dependent - most commonly bytes, but
sometimes "words". You can deal with this by doing an iolength inquiry
on something that you know the size of and then using that result to
normalize with. A second somewhat obscure problem is that iolength tells
you a record size that will work. There could be systems where record
sizes can't be completely arbitrary - for instance they might be
constrained to be even multiples of 4 bytes or some such. In those
cases, the needed record size would include some pad. You could probably
work around that by inquiring about the size needed for an appropriately
sized array of the type instead of a scalar. That would be a bit of
bother, but should work. I've not actually run into this problem, but
could imagine it. Oh, and one last piece of trivia. Technically, a
variable used in a iolength inquiry must have a defined value even
though you never use the value; that's mostly a silly quirk in the way
the standard defines it (it is an output i/o list - variables in output
i/o lists have to be defined), but I've seen at least one compiler gripe
when I had a variable that I declared solely for the purpose and hadn't
bothered to initialize.

3. Hmm. I was thinking that there were 3, but I can't come up with
another off the top of my head right now. Perhaps I misrecall.

Other notes.

David Flower's equivalence trick relies on a nonstandard equivalence.
I'm not at all sure that all compilers will accept that, so be careful.
I have certainly run into compilers that wouldn't, though they might
have subsequently been liberalized to allow such with an appropriate
compiler switch. It has been a while since I looked. (But it is a nifty
trick).

David Frank's solution is portable to all compilers conforming to the
"standard". Unfortunately, that's for David Frank's (I first wrote
"David's" here, but then I realized that was ambiguous and that even
"David F" didn't disambiguate it) definition of "standard", which isn't
the same as the ISO definition. :-( See many previous threads. In
particular, it doesn't include the compilers that you named as needed.
(In fact, mostly that definition of "standard" includes only one
compiler, though which one it is has varied over the years).

--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain | experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
Rich Townsend

2005-08-09, 5:03 pm

Richard E Maine wrote:

> David Frank's solution is portable to all compilers conforming to the
> "standard". Unfortunately, that's for David Frank's (I first wrote
> "David's" here, but then I realized that was ambiguous and that even
> "David F" didn't disambiguate it) definition of "standard", which isn't
> the same as the ISO definition. :-( See many previous threads. In
> particular, it doesn't include the compilers that you named as needed.
> (In fact, mostly that definition of "standard" includes only one
> compiler, though which one it is has varied over the years).
>


In fact, I'm running a book on what the new standard compiler will be,
since -- with CVF's demise -- it can't be long before David switches.

The obvious one is IVF, but ideology may get in the way...

:)
Steven G. Kargl

2005-08-09, 5:03 pm

In article <1123578801.537835.283580@g14g2000cwa.googlegroups.com>,
"David Flower" <DavJFlower@AOL.COM> writes:
>
> guilhem.bonnefille@c-s.fr wrote:
>
> How about :
>
> <your type> X(2)
> INTEGER*1 I(33), L
> DATA I /0, 1, 2, etc. 31, 32/
> EQUIVALENCE ( X, I )
> EQUIVALENCE ( L, X(2) )
>
> L should now contain the required value; note that this should work
> under any version of FORTRAN that supports an integer*1 (or BYTE) type.


I could be wrong, so you've been warned. While the above code
may work in practice, I believe that it is noncondforming to the
the standard.

--
Steve
http://troutmask.apl.washington.edu/~kargl/
Richard E Maine

2005-08-09, 5:03 pm

In article <ddalpu$fpd$1@gnus01.u.washington.edu>,
kargl@troutmask.apl.washington.edu (Steven G. Kargl) wrote:

> I could be wrong, so you've been warned. While the above code
> may work in practice, I believe that it is noncondforming to the
> the standard.


You (Steven) are definitely right. The standard is pretty picky about
what kinds of things are allowed with equivalence. In the early days of
f90, I recall being surprised at quite how picky it was. The way it came
to my attention was that some compilers were rejecting my code. It
hadn't even occurred to me to look for restrictions like that; I just
assumed (incorrectly) that it was ok.

My attempts weren't even this complicated (not that this is very
complicated). I was just trying to do things like byte swapping by
equivalencing an integer(kind=i4_kind) with an array of 4
integer(kind=i1_kind), with appropriate definitions of i4_kind and
i1_kind. No joy.

--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain | experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
David Frank

2005-08-09, 5:03 pm


"Rich Townsend" <rhdt@barVOIDtol.udel.edu> wrote in message
news:ddaj5s$95u$1@scrotar.nss.udel.edu...
> Richard E Maine wrote:
>
>
> In fact, I'm running a book on what the new standard compiler will be,
> since -- with CVF's demise -- it can't be long before David switches.
>
> The obvious one is IVF, but ideology may get in the way...
>
> :)


FYI, I use the phrase "current Fortran standard" interchangeably with F2003
and invite everyone
to do the same..

C_LOC is a current standard function that AFAIK is specified to be identical
in operation to LOC function,
(an extension provided by several/many? current compilers including CVF)


James Van Buskirk

2005-08-09, 5:03 pm

"David Frank" <dave_frank@hotmail.com> wrote in message
news:7q0Ke.2881$RZ2.2852@newsread3.news.atl.earthlink.net...

> integer(1) :: idat(9999)


Good to see that you're starting to use TRANSFER for everything
as you should, but this line is lacking in a couple of ways:

o On some compilers, integer(1) doesn't give you a single-byte
integer.

o There is no need to declare such a big array. Thus, even

integer, parameter :: ik1 = selected_int_kind(2)
integer(ik1) :: idat(0)

might be more generally useful.

--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


David Frank

2005-08-26, 7:57 am


"James Van Buskirk" <not_valid@comcast.net> wrote in message
news:ctSdndb2CJFQcGXfRVn-2g@comcast.com...

> On some compilers, integer(1) doesn't give you a single-byte
> integer.


Really, what idiot compiler would that be, and is it currently being
sold?


Rich Townsend

2005-08-26, 7:57 am

David Frank wrote:
> "James Van Buskirk" <not_valid@comcast.net> wrote in message
> news:ctSdndb2CJFQcGXfRVn-2g@comcast.com...
>
>
>
>
> Really, what idiot compiler would that be, and is it currently being
> sold?
>
>


The F2003 standard does not specify any correspondence between KIND
values and the size (in bytes) of variables. In fact, the only mention
of the word 'byte' in the standard is in the example code in Section
C.10.2.3, "Example of callung C function with non-interoperable data".

This is why the SELECTED_* intrinsics exist.

The NAG compiler has the following KIND values for integers:

1 : 8 bytes
2 : 16 bytes
3 : 32 bytes

So, even though KIND=1 corresponds to a byte, KIND=3 does not correspond
to 3 bytes. I've never had a single problem porting my code to NAG,
since I use the SELECTED_* intrinsics throughout.

cheers,

Rich
David Frank

2005-08-26, 6:59 pm


"Rich Townsend" <rhdt@barVOIDtol.udel.edu> wrote in message
news:den0kr$m8e$1@scrotar.nss.udel.edu...
> David Frank wrote:

<snip> rambling about NAG
[color=darkred]
> So, even though KIND=1 corresponds to a byte,



So you dont know a compiler where integer(1) is not a single byte.


James Van Buskirk

2005-08-26, 6:59 pm

"David Frank" <dave_frank@hotmail.com> wrote in message
news:FzBPe.2353$FW1.1477@newsread3.news.atl.earthlink.net...

> Really, what idiot compiler would that be, and is it currently being
> sold?


The original Sun compiler didn't have single- or double-byte
integers. As your adjectival usage indicates, this wasn't a
particularly popular feature.

--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


Jan Vorbrüggen

2005-08-31, 7:56 am

> The original Sun compiler didn't have single- or double-byte
> integers. As your adjectival usage indicates, this wasn't a
> particularly popular feature.


I believe that was the compiler derived from Cray's.

To add insult to injury, if you declared you variable with the
standard-conforming INTEGER(1) form, it said nothing but silently
used four bytes nonetheless. However, if you used the non-standard
INTEGER*1 form, it at least told you what it was doing...

One shouldn't put error messages into the lexer.

Jan

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com