Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Use of VARYING attribute

bdrichards
Beginner
825 Views
I need some assistance in calling a C++ lib that has a function that accepts a variable number of arguments (this call worked about 6 years ago with the Watcom compiler).
The function in the C++ lib is declared as:
struct resbuf *acutBuildList (int rtype, ...);


and my interface in a mod file is as such:

function acutbuildlist (  )
       integer*4 acutbuildlist
!DEC$ ATTRIBUTES C,varying, ALIAS : '_acutBuildList' :: acutbuildlist 
      end function


and my call to the function in the application is:

pt(1) =0.0;pt(2)=0.0;pt(3)=0.0
iads = acutBuildlist(rtdxf0,'CIRCLE',10,pt,40,1.0,0)


However, the call causes an AV.
Any suggestions?
Bill D. Richards
North Idaho College
0 Kudos
10 Replies
Jugoslav_Dujic
Valued Contributor II
825 Views
Looks fine on first sight. However, I'm suspicious about the string argument ('CIRCLE'). Even if C and VARYING are specified, I think string length is still passed; you'll need REFERENCE attribute for corresponding argument. Even if it's not, I don't see you've NULL-terminated 'CIRCLE', which is what I'd normally expect when calling a C routine.

Is it really a varying "unlimited" number of arguments (as in printf) or the function has a limited number of "modes" of calling (e.g. if rtype is 1, then it expects {char*, float*, int, int} and if rtype is 2, then it expects {int*, int, int} )? If the latter, you may be better off by specifying more generic names for the same procedure, but the same ALIAS, e.g.:
interface acutBuildList
   integer(4) function acutBuildList_1(rtype, string, f1, i1, i2)
   !DEC$ATTRIBUTES C, ALIAS:: '_acutBuildList':: acutBuildList_1
   integer rtype
!DEC$ATTRIBUTES REFERENCE:: string
   character(*) string
   real:: f1(*)
   integer i1,i2
   end function
   
   integer(4) function acutBuildList_2(rtype, i1, i2, i3)
   !DEC$ATTRIBUTES C, ALIAS:: '_acutBuildList':: acutBuildList_2
   ...
   end function
end interface

at least, you'll get better typechecking.

Jugoslav
0 Kudos
bdrichards
Beginner
825 Views
Yes, it is intended to be a varying "unlimited" number of arguments as in printf. And yes, I did fail to place the null-terminator on the string, it should have been: 'CIRCLE'C
I will test to see if this is causing the AV. I am not sure how to specify that the string arguments be passed by reference when there is no explicit interface specifying the order of the arguments. Can you force *pass-by-reference* in the actual argument list itself?

Thanks for the assistance
Bill D. Richards
North Idaho College
0 Kudos
Jugoslav_Dujic
Valued Contributor II
825 Views
Yes, you can use LOC(string) or %REF(string) in the argument list.
0 Kudos
Steven_L_Intel1
Employee
825 Views
My understanding is that the C "..." syntax means that a data structure is passed which contains the number of arguments and then an array of the arguments themselves (values or pointers). Otherwise, there's no mechanism available to know how many arguments were passed. You would need to reconstruct this data structure on the CVF side. You'd probably have to study the MSVC documentation to see what it looks like.

The CVF VARYING attribute exists to allow you to declare an interface for a routine which can be called with a varying number of arguments without using OPTIONAL. It is not the same as C's "...".

Steve
0 Kudos
Jugoslav_Dujic
Valued Contributor II
825 Views
Hmmm, are you sure Steve? My reading of documentation is identical to Bill's, i.e. that the VARYING is invented for specifying INTERFACEs to C (...) routines. Standard C macros va_start and va_arg (roughly corresponding to LOC(FirstArg) + n*PTR_SIZE) can be used to access arguments; of course, end of the list must be determined in some user-defined means. Further, you can hardly write a VARYING routine in Fortran -- IMO only real use for VARYING could be in INTERFACEs to C routines.

I'll try to perform some tests and I'll come back if I come to anything interesting.
0 Kudos
Jugoslav_Dujic
Valued Contributor II
825 Views
Ok, to (try to) prove my point, here's a sample that works:
PROGRAM Varying

IMPLICIT NONE

REAL::            g = 8.98
INTEGER::         k = 42 
CHARACTER(10)::   sz="  See?"c

!Few compiler warnings here but it works
CALL Printf(LOC("AIF"C), LOC("AIF"C), 7, 22.)
CALL Printf(LOC("FFIA"C), g, 15.868, 11, LOC(sz))

CONTAINS
!----------------------
!A simple Printf routine.
!This is a Fortran routine where only syntax has left of Fortran --
!it's a pure C spirit with Crays 

SUBROUTINE Printf(lpFormat)
!DEC$ATTRIBUTES C, VARYING::  Printf

INTEGER, INTENT(IN)::        lpFormat

CHARACTER(100)::  sFormat; POINTER(psFormat,sFormat)
CHARACTER(10)::   s; POINTER(ps,s)
REAL::            f; POINTER(pf,f)
INTEGER::         k; POINTER(pk,k)
INTEGER::         i

i=1
psFormat = lpFormat
DO WHILE(sFormat(i:i).NE.CHAR(0))
   SELECT CASE(sFormat(i:i))
   CASE('a','A')
      !This is what va_arg does:
      pk = LOC(lpFormat) + 4*i
      !char* must be dereferenced once more
      ps = k
      WRITE(*,'(A)',ADVANCE="NO") s(1:INDEX(s,CHAR(0)))
   CASE('i','I')
      pk = LOC(lpFormat) + 4*i
      WRITE(*,'(i4)',ADVANCE="NO") k
   CASE('f','F')
      pf = LOC(lpFormat) + 4*i
      WRITE(*,'(f10.4)',ADVANCE="NO") f
   END SELECT
   i=i+1
END DO
WRITE(*,*)

END SUBROUTINE Printf

END PROGRAM Varying
Jugoslav
0 Kudos
Steven_L_Intel1
Employee
825 Views
Jugoslav,

You seem to have proved my point, but not yours. Let me know when you figure out how to call a C varargs routine from CVF. I'm sure it's possible, but it isn't simply a case of throwing VARYING into the attributes directive.

Steve
0 Kudos
bdrichards
Beginner
825 Views
Steve,
Although I do not have near the experience needed to debate the point, I do believe the VARYING attribute in my INTERFACE module has allowed me to access those functions in the C++ libraries that I am linking against. In looking at the docs for those libraries (part of the AutoCAD 2002 SDK), the funtions expect an argument list as follows:

Each argument is preceeded with an integer*4 code that identifies the type of data that is immediately next in the list and the last argument is a 0 (zero).

By passing all of the strings with LOC('string'C) and paying attention to make sure the numeric types are as expected (4-byte or 2-byte integers, float or double, array of doubles, etc) I seem to be able to use the function calls. Am I just dodging bullets here? Each of my tests seems successful and the app is being put to the real test at a geological survey mapping lab today (with no frantic phone calls,yet).
Thanks for all the ideas, though.
Bill D. Richards
North Idaho College
0 Kudos
Steven_L_Intel1
Employee
825 Views
Bill,

What you're doing looks fine. I'm not a C expert, but I thought that "..." was used for the "varargs" construct - maybe that's something else?

Steve
0 Kudos
Jugoslav_Dujic
Valued Contributor II
825 Views
Steve,
See va_arg entry in MSDN, especially the sample at the end -- it's structurally identical to my sample above. vararg seems to be some VB stuff. OTOH, if I omit VARYING from my sample above, I get errors, not warnings (which are consequence of lack of ellipsis-construct in Fortran).

Jugoslav
0 Kudos
Reply