Code Comments
Programming Forum and web based access to our favorite programming groups."Rob Crain" <r.a.crain@durham.ac.uk> wrote in message news:fsokhs$kda$1@heffalump.dur.ac.uk... > Since it's not mission critical and I'm pushed for time I opted for an > inelegant select case statement; it does the job. Thanks to all for your > responses though - when I get time to tune the code I'll revisit Dick's > suggestion, it looks like it might be the answer. Since C binding was introduced, you can point at any TARGET with any kind of pointer you want, just like in C. C:\gfortran\clf\fake_label>type fake_label.f90 module fake_label_mod implicit none private integer, parameter :: circle_label_len = 20 public circle_datatype type circle_datatype real radius real x real y real z character(len=circle_label_len) circle_label end type circle_datatype end module fake_label_mod program fake_label use fake_label_mod use ISO_C_BINDING implicit none type(circle_datatype), target :: circle1 real, pointer :: pcircle1(:) integer i call C_F_POINTER(C_LOC(circle1), pcircle1, [4]) pcircle1 = [(i,i=3,15,4)] circle1%circle_label = "It's a circle" write(*,*) circle1 end program fake_label C:\gfortran\clf\fake_label>c:\gfortran\win64\bin\x86_64-pc-mingw32-gfortran fake _label.f90 -ofake_label C:\gfortran\clf\fake_label>fake_label 3.0000000 7.0000000 11.000000 15.000000 It's a circle Thus in the above I have pointed at the four REAL elements of circle1 with a pointer to an array of REALs, and accessed them as an array of REALs. -- write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & 6.0134700243160014d-154/),(/'x'/)); end
Post Follow-up to this messageJames Van Buskirk <not_valid@comcast.net> wrote: > Since C binding was introduced, you can point at any TARGET with > any kind of pointer you want, just like in C. And just like in C, that doesn't actually mean it is standard conforming or portable. It just means that the compiler isn't likely to XXXXX about it; whether it works as intended is another matter entirely. > Thus in the above I have pointed at the four REAL elements of circle1 > with a pointer to an array of REALs, and accessed them as an array > of REALs. Yep. Odds are even fairly good that it will work in most environments. But it is *NOT* standard conforming. If you find an environment where it fails, you'll have no recourse. The standard doesn't specify that the components are stored in that way. This isn't even a matter of having to read the whole standard and concluding that one couldn't find such a specification. The standard explicitly says that there is no such specification. You might improve the odds by making the type a sequence type. Even then, it isn't guaranteed because the type wouldn't be a numeric sequence. You might improve them even more by making it a bind(c) type. I don't recall C's rules on this kind of thing. -- Richard Maine | Good judgement comes from experience; email: last name at domain . net | experience comes from bad judgement. domain: summertriangle | -- Mark Twain
Post Follow-up to this messageRichard Maine wrote:
> James Van Buskirk <not_valid@comcast.net> wrote:
> And just like in C, that doesn't actually mean it is standard conforming
> or portable. It just means that the compiler isn't likely to XXXXX about
> it; whether it works as intended is another matter entirely.
(snip)
> You might improve them even more by making it a bind(c) type. I don't
> recall C's rules on this kind of thing.
The one I remember is that a pointer to a struct is equal to a
pointer to the first element. While padding is allowed, consecutive
elements of the same type should not need padding. (I am not sure
that the standard says that, though.) Note that any required
padding is always included in each element. That is, the sizeof
a struct (or any type) includes any padding needed to make an array
out of that type.
The easy answer in C is to make it an array and #define the members:
struct c { double coord[3];};
#define x coord[0]
#define y coord[1]
#define z coord[2]
-- glen
Post Follow-up to this messageOn 2 avr, 15:19, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
> Richard Maine wrote:
>
> (snip)
>
>
> The one I remember is that a pointer to a struct is equal to a
> pointer to the first element. While padding is allowed, consecutive
> elements of the same type should not need padding. (I am not sure
> that the standard says that, though.) Note that any required
> padding is always included in each element. That is, the sizeof
> a struct (or any type) includes any padding needed to make an array
> out of that type.
>
> The easy answer in C is to make it an array and #define the members:
>
> struct c { double coord[3];};
>
> #define x coord[0]
> #define y coord[1]
> #define z coord[2]
>
> -- glen
My proposal:
integer, parameter :: radius = 0
integer, parameter :: x = 1
integer, parameter :: y = 2
integer, parameter :: z = 3
type circle_datatype
real :: f(0:3)
character(len=...) :: circle_label
endtype circle_datatype
type(circle_datatype) :: circle
circle%f(radius) = ...
circle%f(0) = ...
Depending on the frequency of access by index or by name, this
solution may be more interesting than a select case.
Post Follow-up to this messageOn Mar 30, 7:30=A0am, Dick Hendrickson <dick.hendrick...@att.net> wrote: > Rob Crain wrote: > > > > > If you don't mind making the code clumsy, error-prone, and difficult > to read, it's trivial ;). > > Create a hidden helper type, something like > =A0 =A0 =A0type helper > =A0 =A0 =A0 =A0 integer =A0:: =A0index > =A0 =A0 =A0 =A0 real =A0 =A0 :: =A0x > =A0 =A0 =A0 =A0 character(len=3Dwhatever) =A0:: =A0c > =A0 =A0 =A0 =A0 ! any other types that are in circle_datatype > =A0 =A0 =A0endtype helper > > Next create some generic operators or functions that return type > helper results. > =A0 =A0 =A0i .func. value > or maybe > =A0 =A0 =A0func(i,value) > returns a type helper result with the index set to i, and the > appropriate x or c set to value. =A0You'll, obviously, need one > function for each type of element in circle_datatype. =A0The > character one is trivial, the real one needs a select case. > > You can then also provide overloads to do arithmetic between > type helper and the intrinsic types, helper types, and > circle_datatype and return type helper. > > =A0 =A0 =A0 (i .func. circle) * 3.14 * (j .func. other_circle)**2 > > Then create an assignment operator that assigns type helper to > type circle by using an internal select case to assign to the > INDEXth element. > > The result is that > =A0 =A0 =A0 =A0circle =3D i .func. value > > is ultimately equivalent to > =A0 =A0 =A0 =A0call assigner(circle, i, value) > > I'm not real happy with putting the circle subscript on the right, > it's ugly and error-prone. =A0But I think it'll work. > > After thinking about this, why not just create a few generic > subroutines that implement the above call if you only want to > do assignments that update (but not use) elements? > > If you're not in a big hurry and can wait until 2008, the new > Fortran allows pointer functions on the left hand side. > You could probably make > =A0 =A0 =A0 circle.element.i =3D whatever > do what you want. =A0But that won't be standard until later this > year. =A0It might take even longer to get a F2008 compiler :(. > > Dick Hendrickson Isn't the solution I posted slightly better/easier than having to define an operator? Or maybe I'm missing something. John.
Post Follow-up to this message
"glen herrmannsfeldt" <gah@ugcs.caltech.edu> wrote in message
news:HfadnRt3I9q_Rm7anZ2dnUVZ_oaonZ2d@co
mcast.com...
> Richard Maine wrote:
>
>
> (snip)
>
>
> The one I remember is that a pointer to a struct is equal to a
> pointer to the first element. While padding is allowed, consecutive
> elements of the same type should not need padding. (I am not sure
> that the standard says that, though.) Note that any required
> padding is always included in each element. That is, the sizeof
> a struct (or any type) includes any padding needed to make an array
> out of that type.
>
> The easy answer in C is to make it an array and #define the members:
>
> struct c { double coord[3];};
>
> #define x coord[0]
> #define y coord[1]
> #define z coord[2]
I've never seen this syntax before. Is it standard c? (Looks like it.)
--
"That this social order with its pauperism, famines, prisons, gallows,
armies, and wars is necessary to society; that still greater disaster
would ensue if this organization were destroyed; all this is said only
by those who profit by this organization, while those who suffer from it
- and they are ten times as numerous - think and say quite the contrary."
~~ Leo Tolstoy
Post Follow-up to this message"Richard Maine" <nospam@see.signature> wrote in message news:1iem5vx.9ffoff14uwzvqN%nospam@see.signature... > You might improve them even more by making it a bind(c) type. I don't > recall C's rules on this kind of thing. Yes, and I thought of declaring the derived type as BIND(C) because it's not C's rules so much as what C itself is supposed to interoperate with that the companion processor is going to emulate. Win32 API in 64-bit mode requires natural alignment of data elements up to 128 bits wide, but a companion processor that is targeting an older version of Windows isn't going to have the same kind of alignment restrictions. The reason I didn't do so in my example lay in section 15.2.1 of N1601.pdf: "... if the type is character, interoperability also requires that the length parameter be omitted or be specified by an initialization expression whose value is one." and further in section 15.2.3: "... the components of the Fortran derived type have types and type parameters that are interoperable with the types of the corresponding components of the struct type." So I think it would create problems because the O.P. seemed to indicate a preference for a character component with nonunit LEN (although what was intended wasn't made precise) so he would have had to have restructured to an array of character*1 which would have had its own syntactic downside in the body of the code. C:\gfortran\clf\bad_len>type bad_len.f90 module bad_len implicit none type, BIND(C) :: bad_type character(4) bad end type bad_type end module bad_len C:\gfortran\clf\bad_len>C:\gcc_equation\bin\x86_64-pc-mingw32-gfortran -Wall -c bad_len.f90 bad_len.f90:4.22: character(4) bad 1 Warning: Component 'bad' in derived type 'bad_type' at (1) may not be C interope rable, even though derived type 'bad_type' is BIND(C) Mmmm, just a warning though. How bad is the above code? -- write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & 6.0134700243160014d-154/),(/'x'/)); end
Post Follow-up to this messageJames Van Buskirk <not_valid@comcast.net> wrote: > "Richard Maine" <nospam@see.signature> wrote in message > news:1iem5vx.9ffoff14uwzvqN%nospam@see.signature... > > > Yes, and I thought of declaring the derived type as BIND(C)... ... > The reason I didn't do so in my example lay in section 15.2.1 of > N1601.pdf: > > "... if the type is character, interoperability also requires that > the length parameter be omitted or be specified by an initialization > expression whose value is one." Yeah. That issue ocurred to me, but I decided that lead into a possibly substantial diversion (as you have seen). I didn't think it worth going down that path as it didn't seem likely to help the OP's question. After all, mixing of character and numeric data in the derived type throws a whole host of extra caveats into the mix such that generalization becomes tricky at best. > the O.P. seemed to > indicate a preference for a character component with nonunit LEN > (although what was intended wasn't made precise) so he would have > had to have restructured to an array of character*1 which would > have had its own syntactic downside in the body of the code. I didn't read that into the OP's post. What I saw was a preference for a form that isn't valid regardless of whether you use a character string or an array of character (namely, that the length or size was unspecified). That seemed like a matter orthogonal to the question asked, so I didn't go into alternatives - just mentioned that it was invalid. The alternatives are...nontrivial. Perhaps the closest in concept might be a parameterized derived type, where objects of the type could have assumed type parameter values. But that's an f2003 feature, and one of the last ones that vendors seem to be implementing. I'm also not sure whether it actually fits the intended use or not. It would sure kill the possibility of also being bind(c). Making the string allocatable length would be another f2003 possibility, depending on the intended use. And allocatable string length seems to be another of the f2003 features that is being slow to get implemented *too bad, as I'm quite find of the feature). Making the string an allocatable size array of char would at least get you down to f95+tr, but would still be incompatible with bind(c). Making the string a pointer to an array of char is legit in plain old f95, but again incompatible with bind(c), and it has all the usual problems with using pointers as a hack to substitute for things like allocatable. > Mmmm, just a warning though. How bad is the above code? Well, it's nonstandard. I couldn't say what the odds of other compilers accepting it would be. It is plausible that they might do the same thing and accept it with a warning. But I couldn't guarantee that. -- Richard Maine | Good judgement comes from experience; email: last name at domain . net | experience comes from bad judgement. domain: summertriangle | -- Mark Twain
Post Follow-up to this message"Richard Maine" <nospam@see.signature> wrote in message news:1iesmwa.1s8zxrwcent9oN%nospam@see.signature... > Making the string allocatable length would be another f2003 possibility, > depending on the intended use. And allocatable string length seems to be > another of the f2003 features that is being slow to get implemented *too > bad, as I'm quite find of the feature). You are not the only one. Writing a getline() function would be a snap with allocatable lengths, impossible with specification expressions. The allocatable lengths seem to be of the same syntactic flavor as parameterized derived types, though, which is probably why they get implemented so late. Maybe I'm just dumb or something, but parameterized derived types don't seem to me to add all that much to the language for all the extra costs they impose on the vendor and for all the stuff the user has to know to make them a useful tool. -- write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, & 6.0134700243160014d-154/),(/'x'/)); end
Post Follow-up to this message"James Van Buskirk" <not_valid@comcast.net> wrote in message news:lIqdnawoRKG6HmnanZ2dnUVZ_sudnZ2d@co mcast.com... > "Richard Maine" <nospam@see.signature> wrote in message > news:1iesmwa.1s8zxrwcent9oN%nospam@see.signature... > > > You are not the only one. Writing a getline() function would be a > snap with allocatable lengths, impossible with specification > expressions. The allocatable lengths seem to be of the same > syntactic flavor as parameterized derived types, though, which is > probably why they get implemented so late. Maybe I'm just dumb or > something, but parameterized derived types don't seem to me to add > all that much to the language for all the extra costs they impose > on the vendor and for all the stuff the user has to know to make > them a useful tool. Dumb people rarely spell parametrized or the other one correctly. I couldn't say which is preferred. -- "That this social order with its pauperism, famines, prisons, gallows, armies, and wars is necessary to society; that still greater disaster would ensue if this organization were destroyed; all this is said only by those who profit by this organization, while those who suffer from it - and they are ten times as numerous - think and say quite the contrary." ~~ Leo Tolstoy
Post Follow-up to this messagePowered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.