Use of VARYING attribute

Use of VARYING attribute

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

11 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

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
   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.


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

Yes, you can use LOC(string) or %REF(string) in the argument list.

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 "...".


Retired 12/31/2016

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.

Ok, to (try to) prove my point, here's a sample that works:



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))

!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)

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

psFormat = lpFormat
DO WHILE(sFormat(i:i).NE.CHAR(0))
   SELECT CASE(sFormat(i:i))
      !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)))
      pk = LOC(lpFormat) + 4*i
      WRITE(*,'(i4)',ADVANCE="NO") k
      pf = LOC(lpFormat) + 4*i
      WRITE(*,'(f10.4)',ADVANCE="NO") f





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.


Retired 12/31/2016

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


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?


Retired 12/31/2016

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).


Leave a Comment

Please sign in to add a comment. Not a member? Join today