- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Now I want to write a subroutine (subroutine A) to realize the following function:
It can accept any type of array (integer, real, real*8, user defined structure) and then pass some of the elements to another subroutine (subroutine B). The data type of the array is unknown for the subroutine A but is known for the subroutine B.
Can you tell me how should I do? Thanks!
It can accept any type of array (integer, real, real*8, user defined structure) and then pass some of the elements to another subroutine (subroutine B). The data type of the array is unknown for the subroutine A but is known for the subroutine B.
Can you tell me how should I do? Thanks!
Link Copied
17 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Should be OK. There are several approaches:
1) Declare it as an integer:
3) See also !DEC$ATTRIBUTES NO_ARG_CHECK:: lParam attribute. It instructs the compiler not to check argument type when placed in a module procedure or interface block.
Jugoslav
1) Declare it as an integer:
call A(1, B) call A((/7, 5, 3/), B) call A(T_POINT(10,10), B) ... subroutine A(lParam, B) integer:: lParam external B ... call B(lParam)2) In approach 1), compiler will give warnings about different parameters. You can suppress them by passing an address of the argument:
call A(LOC(1), B) call A(LOC((/7, 5, 3/)), B) call A(LOC(T_POINT(10,10)), B) ... subroutine A(lParam, B) integer:: lParam external B ... call B(%VAL(lParam))Here, you need %VAL to avoid double indirection (i.e. not to read LOC(LOC(argument))).
3) See also !DEC$ATTRIBUTES NO_ARG_CHECK:: lParam attribute. It instructs the compiler not to check argument type when placed in a module procedure or interface block.
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you very much!
Here I dont want to pass the whole array from A to B, I only want to pass some of its elements.
I will realize:
module test
type data0
integer a,b
real*8 c
end type
end module
use test
type(data0)mydata(100)
call A(mydata,100,B)
end
integer function B(b1,b2)
use test
type(data0)b1,b2
...
Here, the returned value B is according to b1 and b2
end
subroutine A(unknowndata, lengthdata, B)
external B
Here, how can I define the unknowndata?
i=1
j=n
do
j=B(unknowndata(i),unknowndata(j))
Can I pass data like this? How can I realize my idea above?
call swap(unknowndata(i),unknowndata(j))
if(...)exit
enddo
end
Here I dont want to pass the whole array from A to B, I only want to pass some of its elements.
I will realize:
module test
type data0
integer a,b
real*8 c
end type
end module
use test
type(data0)mydata(100)
call A(mydata,100,B)
end
integer function B(b1,b2)
use test
type(data0)b1,b2
...
Here, the returned value B is according to b1 and b2
end
subroutine A(unknowndata, lengthdata, B)
external B
Here, how can I define the unknowndata?
i=1
j=n
do
j=B(unknowndata(i),unknowndata(j))
Can I pass data like this? How can I realize my idea above?
call swap(unknowndata(i),unknowndata(j))
if(...)exit
enddo
end
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Huh... now we're coming to a slippery ground.
You're trying to implement something like QSORT, don't you? In my first reply, I assumed that A does not need to know anything about the data -- just that it's an address of some data which should be passed through. However, in your second example, A needs to know that unknowndata is an array, ergo it has to know size of each element to be able to reference it properly, and to know its bounds.
This is much better suited for low-level language like C, where you can go down to hardware addresses and disregard typechecking. I bet QSORT/SORTQQ is actually implemented in C.
Here's a piece of Fortran code which may do what you want, but it's rather C-like, in that it deals with raw bytes rather than with higher-level concepts:
It's all easier to do without explicit interfaces, as you don't want the compiler to check validity of arguments.
Note expressions (i-1)*sizeofdata+1. If sizeofdata is e.g. 8 bytes, for i=1 it will give 1, for i=2 it will be 9, i.e. first member starts on byte 1, the second on byte 9 etc.
Jugoslav
You're trying to implement something like QSORT, don't you? In my first reply, I assumed that A does not need to know anything about the data -- just that it's an address of some data which should be passed through. However, in your second example, A needs to know that unknowndata is an array, ergo it has to know size of each element to be able to reference it properly, and to know its bounds.
This is much better suited for low-level language like C, where you can go down to hardware addresses and disregard typechecking. I bet QSORT/SORTQQ is actually implemented in C.
Here's a piece of Fortran code which may do what you want, but it's rather C-like, in that it deals with raw bytes rather than with higher-level concepts:
subroutine A(unknowndata, lengthdata, sizeofdata, B)
external B
integer(1) unknowndata(lengthdata*sizeofdata)
i=1
j=n
do
j=B(unknowndata((i-1)*sizeofdata+1), &
unknowndata((j-1)*sizeofdata+1))
call swap(unknowndata((i-1)*sizeofdata+1), &
unknowndata((j-1)*sizeofdata+1))
if(...)exit
enddo
endand pass sizeof(A) of type data0 to A as sizeofdata argument. See considerations on QSORT entry in CVF docs.It's all easier to do without explicit interfaces, as you don't want the compiler to check validity of arguments.
Note expressions (i-1)*sizeofdata+1. If sizeofdata is e.g. 8 bytes, for i=1 it will give 1, for i=2 it will be 9, i.e. first member starts on byte 1, the second on byte 9 etc.
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you very much!
I just want to realize the function of QSORT in CVF, but the array in it can't be structure.
From you reply, I can see you are an expert in Fortran. I hope I can conmmunicate with you in future. I am from China and my e-mail is tangzhanghong98@yahoo.com. Would you please tell me yours?
I just want to realize the function of QSORT in CVF, but the array in it can't be structure.
From you reply, I can see you are an expert in Fortran. I hope I can conmmunicate with you in future. I am from China and my e-mail is tangzhanghong98@yahoo.com. Would you please tell me yours?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I just want to realize the function of QSORT in CVF, but the array in it can't be structure.
Oh yes it can -- you only need few tricks. Please open DFPORT.f90 from your ...Microsoft Visual StudioDF98Include folder -- there's a thorough comment.
The catch there is that INTERFACE for QSORT is explicit (in module DFPORT). To convince compiler that you really mean to call QSORT with varying types of arguments, a generic interface is defined (one name QSORT for several routines, in this case $$msportlib$qsorti1, $$msportlib$qsorti2 etc.). Then, every of these $$ routines is mapped to the same routine using !DEC$ATTRIBUTES alias:'_QSORT@16'. That means that there's only one implementation of QSORT (to be found in DFPORT.lib, probably written in C), and the generic interface specifies all "correct" means to call it (with integer(1), real, integer(2) etc.). If you want your own derived type, you must redefine (add your own) interface to the set.
I suggested avoiding an explicit interface for sake of simplicity (you get cleaner, but more complicated code with it). If QSORT is really what you're looking for, you can just call it:
call QSORT(YourStructArray(1), YourArrayLength, SIZEOF(YourStructArray(1)), YourComparFunc)
provided that you don't USE DFPORT -- if you do, the compiler will complain that "There's no specific procedure for this generic call" or sort, since YourStruct is not in the list of "correct" arguments. Only, make sure that DFPORT.lib is linked -- I think it is by default.
My e-mail address is jdujic -at- uns.ns.ac.yu. (I avoid leaving it on the net as-is to avoid spammers).
Jugoslav
Oh yes it can -- you only need few tricks. Please open DFPORT.f90 from your ...Microsoft Visual StudioDF98Include folder -- there's a thorough comment.
The catch there is that INTERFACE for QSORT is explicit (in module DFPORT). To convince compiler that you really mean to call QSORT with varying types of arguments, a generic interface is defined (one name QSORT for several routines, in this case $$msportlib$qsorti1, $$msportlib$qsorti2 etc.). Then, every of these $$ routines is mapped to the same routine using !DEC$ATTRIBUTES alias:'_QSORT@16'. That means that there's only one implementation of QSORT (to be found in DFPORT.lib, probably written in C), and the generic interface specifies all "correct" means to call it (with integer(1), real, integer(2) etc.). If you want your own derived type, you must redefine (add your own) interface to the set.
I suggested avoiding an explicit interface for sake of simplicity (you get cleaner, but more complicated code with it). If QSORT is really what you're looking for, you can just call it:
call QSORT(YourStructArray(1), YourArrayLength, SIZEOF(YourStructArray(1)), YourComparFunc)
provided that you don't USE DFPORT -- if you do, the compiler will complain that "There's no specific procedure for this generic call" or sort, since YourStruct is not in the list of "correct" arguments. Only, make sure that DFPORT.lib is linked -- I think it is by default.
My e-mail address is jdujic -at- uns.ns.ac.yu. (I avoid leaving it on the net as-is to avoid spammers).
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you very much again!
I have tried with the method you give below, but when Compiling, there are an error:
Error: There is no matching specific subroutine for this generic subroutine call. [SORT]
call sort(site0,npoint,sizeof(site0(1)),bigger)
How can I solve this problem?
For your last reply, I also know, but I would like to write my own code, and I believe I would not use this method only to QSORT.
Thanks!
Tang, Zhanghong
I have tried with the method you give below, but when Compiling, there are an error:
Error: There is no matching specific subroutine for this generic subroutine call. [SORT]
call sort(site0,npoint,sizeof(site0(1)),bigger)
How can I solve this problem?
For your last reply, I also know, but I would like to write my own code, and I believe I would not use this method only to QSORT.
Thanks!
Tang, Zhanghong
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Did you mean QSORT? Or is SORT your own routine?
If it's QSORT, as I said, you'll get this error if you USE DFPORT. Writing a call without USE DFPORT compiles cleanly on my computer. Alternatively, you can USE DFPORT, but you have to redefine the generic interface as stated in comments in DFPORT.f90.
Similarly, if it's your routine, if it's in a module, you would get a similar error.
Usually, one wants to place routines in MODULEs and USE them, because it enforces strict typechecking, so you can't make accidental argument type mismatch. However, in your case, you want a reverse -- you have a routine which generically deals with any datatype and don't want the compiler to "do you a favor". So, subroutine A, as I wrote earlier, should work if it's in a source file separate from the caller.
Jugoslav
If it's QSORT, as I said, you'll get this error if you USE DFPORT. Writing a call without USE DFPORT compiles cleanly on my computer. Alternatively, you can USE DFPORT, but you have to redefine the generic interface as stated in comments in DFPORT.f90.
Similarly, if it's your routine, if it's in a module, you would get a similar error.
Usually, one wants to place routines in MODULEs and USE them, because it enforces strict typechecking, so you can't make accidental argument type mismatch. However, in your case, you want a reverse -- you have a routine which generically deals with any datatype and don't want the compiler to "do you a favor". So, subroutine A, as I wrote earlier, should work if it's in a source file separate from the caller.
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear Sir,
Thank you very much!
I want to write my own sort code! Here I paste a simple list of codes. Would you please tell me what I should do?
Thanks!
Sincerely,
Tang, Zhanghong
module my_sort
interface sort
module procedure sortall
end interface
contains
subroutine sortall(DATA,N,NSIZE,comp)
integer*1 data(1)
integer*1 tempdata(nsize)
logical*1, external:: comp
i=1
j=100
if(comp(data((i-1)*nsize+1),data((j-1)*nsize+1)))then
! swap
tempdata=data((i-1)*nsize+1:i*nsize)
data((i-1)*nsize+1:i*nsize)=data((j-1)*nsize+1:j*nsize)
data((j-1)*nsize+1:j*nsize)=tempdata
endif
end subroutine
end module
module userdefine
type point
real*8 x,y
integer idx
end type
end module
program main
use my_sort
use userdefine
type(point)coord(1000)
! read data
call sort(coord,1000,sizeof(coord(1)),comp)
end
logical*1 function comp(p1,p2)
use userdefine
type(point)p1,p2
if(p1.y comp=.false.
elseif(p1.y>p2.y)then
comp=.true.
elseif(p1.x comp=.false.
elseif(p1.x>p2.x)then
comp=.true.
endif
end
Thank you very much!
I want to write my own sort code! Here I paste a simple list of codes. Would you please tell me what I should do?
Thanks!
Sincerely,
Tang, Zhanghong
module my_sort
interface sort
module procedure sortall
end interface
contains
subroutine sortall(DATA,N,NSIZE,comp)
integer*1 data(1)
integer*1 tempdata(nsize)
logical*1, external:: comp
i=1
j=100
if(comp(data((i-1)*nsize+1),data((j-1)*nsize+1)))then
! swap
tempdata=data((i-1)*nsize+1:i*nsize)
data((i-1)*nsize+1:i*nsize)=data((j-1)*nsize+1:j*nsize)
data((j-1)*nsize+1:j*nsize)=tempdata
endif
end subroutine
end module
module userdefine
type point
real*8 x,y
integer idx
end type
end module
program main
use my_sort
use userdefine
type(point)coord(1000)
! read data
call sort(coord,1000,sizeof(coord(1)),comp)
end
logical*1 function comp(p1,p2)
use userdefine
type(point)p1,p2
if(p1.y
elseif(p1.y>p2.y)then
comp=.true.
elseif(p1.x
elseif(p1.x>p2.x)then
comp=.true.
endif
end
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The whole point is that body of sortall should not be in a module -- otherwise, the compiler will see that the first argument is an integer(1) array and complain.
In any case, move the body of sortall into a separate source file which is not a module -- just subroutine...end subroutine.
Then,
1) Method 1 (simpler) (F77-style)
Get rid of Module my_sort altogether (both body and uses).
Just CALL Sortall with an array of POINTs.
2) Method 2 (F90-style)
Write an interface block to sortall in module my_sort:
Jugoslav
In any case, move the body of sortall into a separate source file which is not a module -- just subroutine...end subroutine.
Then,
1) Method 1 (simpler) (F77-style)
Get rid of Module my_sort altogether (both body and uses).
Just CALL Sortall with an array of POINTs.
2) Method 2 (F90-style)
Write an interface block to sortall in module my_sort:
module my_sort interface sort subroutine sort_point(data,n,nsize,comp) !sort_point is just a dummy name which is an !alias to SORTALL you wrote: !dec$attributes default, decorate, alias: "SORTALL":: sort_point use userdefine type(point):: data(*) integer:: n, nsize logical(1), external:: comp end subroutine !Place similar interface block here if you need !sort_something_else end interface end module ... program main use my_sort use userdata type(point)coord(1000) call sort(coord, 1000, sizeof(coord(1)), comp) end program
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you for your reply so soon!
The question is that in the subroutine of sort_point, I don't know the datatype defined in "userdefine", so we can't write use userdefine and type(point)::data(*). Isn't it?
Tang, Zhanghong
The question is that in the subroutine of sort_point, I don't know the datatype defined in "userdefine", so we can't write use userdefine and type(point)::data(*). Isn't it?
Tang, Zhanghong
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
True -- if user adds a new type to userdefine, he has to add an INTERFACE in sort_data as well.
That's why I recommended not using modules/interfaces at all -- it's much simpler.
Jugoslav
That's why I recommended not using modules/interfaces at all -- it's much simpler.
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you very much!
I have tested your first method, link is successful. But when running, it appears "forrtl: severe <172>: ..."
my modified code is below:
!module my_sort
! interface sort
subroutine sortall(DATA,N,NSIZE,comp)
!dec$attributes default, decorate, alias: "SORTALL":: sortall
integer*1 data(1)
integer*1 tempdata(nsize)
logical*1, external:: comp
i=1
j=2
if(comp(data((i-1)*nsize+1),data((j-1)*nsize+1)))then
! swap
tempdata=data((i-1)*nsize+1:i*nsize)
data((i-1)*nsize+1:i*nsize)=data((j-1)*nsize+1:j*nsize)
data((j-1)*nsize+1:j*nsize)=tempdata
endif
end subroutine
! end interface
!end module
module userdefine
type point
real*8 x,y
integer idx
end type
end module
program main
!use my_sort
use userdefine
type(point)coord(2)
! read data
coord(1).x=1.;coord(1).y=-1.;coord(1).idx=1
coord(2).x=2.;coord(2).y=-2.;coord(2).idx=2
call sortall(coord,2,sizeof(coord(1)),comp)
end
logical*1 function comp(p1,p2)
use userdefine
type(point)p1,p2
if(p1.y comp=.false.
elseif(p1.y>p2.y)then
comp=.true.
elseif(p1.x comp=.false.
elseif(p1.x>p2.x)then
comp=.true.
endif
end
I have tested your first method, link is successful. But when running, it appears "forrtl: severe <172>: ..."
my modified code is below:
!module my_sort
! interface sort
subroutine sortall(DATA,N,NSIZE,comp)
!dec$attributes default, decorate, alias: "SORTALL":: sortall
integer*1 data(1)
integer*1 tempdata(nsize)
logical*1, external:: comp
i=1
j=2
if(comp(data((i-1)*nsize+1),data((j-1)*nsize+1)))then
! swap
tempdata=data((i-1)*nsize+1:i*nsize)
data((i-1)*nsize+1:i*nsize)=data((j-1)*nsize+1:j*nsize)
data((j-1)*nsize+1:j*nsize)=tempdata
endif
end subroutine
! end interface
!end module
module userdefine
type point
real*8 x,y
integer idx
end type
end module
program main
!use my_sort
use userdefine
type(point)coord(2)
! read data
coord(1).x=1.;coord(1).y=-1.;coord(1).idx=1
coord(2).x=2.;coord(2).y=-2.;coord(2).idx=2
call sortall(coord,2,sizeof(coord(1)),comp)
end
logical*1 function comp(p1,p2)
use userdefine
type(point)p1,p2
if(p1.y
elseif(p1.y>p2.y)then
comp=.true.
elseif(p1.x
elseif(p1.x>p2.x)then
comp=.true.
endif
end
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You're missing
I.e. a real variable comp was generated, instead of reference to function comp. IMPLICIT NONE would have helped :-).
Jugoslav
program main !use my_sort use userdefine type(point)coord(2) logical(1), external:: comp
I.e. a real variable comp was generated, instead of reference to function comp. IMPLICIT NONE would have helped :-).
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Oh, dear!
Thank you very very much!! I have successed!
But normally I wish the general code which is suitable for any datatype become a libaray and user can use it conveniently. Should I build it into static library(LIB) or dynamic library(DLL)?
Thank you very very much!! I have successed!
But normally I wish the general code which is suitable for any datatype become a libaray and user can use it conveniently. Should I build it into static library(LIB) or dynamic library(DLL)?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
...or source code as-is :-).
There's no general answer. LIBs are probably simplest to use, but they're mostly not cross-compatible amongst compilers (if I got Steve well, IVF 8 won't be lib-compatible with CVF 6?). The most convenient form for the end-user would probably be source code -- he can examine or modify it (of course, if you let him so). I don't think dll would be a good idea in this context -- it would have to be redistributed along with user's .exes.
I think the best combination would be to provide both .lib (for "lazy" users) and source files (for "more advantageous").
Jugoslav
There's no general answer. LIBs are probably simplest to use, but they're mostly not cross-compatible amongst compilers (if I got Steve well, IVF 8 won't be lib-compatible with CVF 6?). The most convenient form for the end-user would probably be source code -- he can examine or modify it (of course, if you let him so). I don't think dll would be a good idea in this context -- it would have to be redistributed along with user's .exes.
I think the best combination would be to provide both .lib (for "lazy" users) and source files (for "more advantageous").
Jugoslav
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Oh, what do you mean? IVF 8? I hear it at first time. Is it the so called a new fortran 2000 complier like CVF? And it adapt the final draft of fortran standard in 2003?
I think you are an expert in Fortran, when I have problems some time later, I would ask you again.
Thanks!
Sincerely,
Tang, Zhanghong
I think you are an expert in Fortran, when I have problems some time later, I would ask you again.
Thanks!
Sincerely,
Tang, Zhanghong
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jugoslav is correct - a static library (.LIB) built with CVF will not be usable with Intel Visual Fortran. Intel Visual Fortran 8.0 (the release due in December) will be, as is CVF, an extended Fortran 95 compiler with some features from the draft of Fortran 2003.
Steve
Steve
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