bagchi@dip.eecs.umich.edu (Ranjan Bagchi) (12/31/89)
I'm working, currently, on a project that involves a function that could take any number or arguments. I would like to pass it only those arguments, i.e. no "flags" at the end which tell the function to stop. I'm using ANSI C, and believe my options are either to pass the function an array, or to use the elipsis for unspecified. The problems with each is that (for the first), given the array I have no way of knowing the size of the array (do I?) given only the array. For the second, I have no idea how to use an elipsis. Any ideas? Thanks...rj bagchi.sparky.eecs.umich.edu (If I'm dealing with something trivial, E-mail, please) ZZ
henry@utzoo.uucp (Henry Spencer) (12/31/89)
In article <1169@zip.eecs.umich.edu> bagchi@dip.eecs.umich.edu (Ranjan Bagchi) writes: > I'm working, currently, on a project that involves a function that >could take any number or arguments. I would like to pass it only >those arguments, i.e. no "flags" at the end which tell the function >to stop. Your function has to have some way of knowing how many arguments there are, or which is the last argument. The language does not provide any built-in way for you to discover this. The usual approaches are a terminator argument of some kind, an argument count passed as the first argument, or an implicit count embodied in an early argument (e.g., you can tell how many arguments a printf() has by analyzing the format string). You have to do one of these things. > I'm using ANSI C, and believe my options are either to pass >the function an array, or to use the elipsis for unspecified. By far the simplest method is to pass an array with either a terminator flag in the array or a count as a separate argument. The ellipsis will not solve the problem for you, and proper use of it is complex. -- 1972: Saturn V #15 flight-ready| Henry Spencer at U of Toronto Zoology 1989: birds nesting in engines | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
amull@Morgan.COM (Andrew P. Mullhaupt) (12/31/89)
I need to make assignment of any number of variables of any type to a temporary stack, and then reassign them back again. I'm at present using two versions (one with varargs.h for System V and one with stdarg.h for ANSI C). I pass the 'return addresses' and sizes of the variables, a single punctuational NULL, and then the list of values as function arguments. I then memcpy the appropriate sizes for the values (indexed just after the NULL marker argument) into the waiting addresses. This (for those who may be interested in speed) is not too slow - on a CISC architecture like the 386 it's only about 2.5 times as much time as the equivalent structure assignment, (which can't be coded because the arguments are not always of some given type), but on a RISC (like a Sun 4) it's about 20 times as slow. (Gack!). Now this business is not without at least one fine point I can't really get around; and that is the size of a variable is not always the same as it's size as an argument passed to a function on a stack. The complicated part (aside from the instant Hell of memory model complications) seems to come when using type char data which gets widened to int. It seems that where your character ends up in the int cannot be known without knowledge of the dreaded byte-ordering of the machine. Also; since there is no way to know at run-time what type the argument has, sizeof isn't so helpful on the way into this function. Essentially, I'm trying to write a 'remember' function which retains the values of any collection of assignable l-values for future re-assignment. The function is of type void, but could be assumed to be called 'recursively' in the sense that evaluation of the r-values may call functions which call 'remember'. Has anyone got a standard or portable way to do this? P.S. Is there some strange side effect of going from System V style varargs to ANSI stdarg which changes the code generation between caller and called? The profile timings of the two otherwise identical versions of a function using 'remember' compiled on the SCO / Microsoft UNIX System V/386 r3.2 C compiler differ in how the time is split between the caller and the called routine. The ANSI version has a faster called routine, but the System V UNIX-style version makes up the difference (nearly exactly) by having a faster caller. Is this due to the dPANS? Thanks in Advance, Andrew Mullhaupt
davidsen@sixhub.UUCP (Wm E. Davidsen Jr) (12/31/89)
henry@utzoo.uucp (Henry Spencer) writes: | Your function has to have some way of knowing how many arguments there | are, or which is the last argument. I have wondered about this. B certainly had this, when I did my first B port, about 15-18 years ago, the GCOS version called via a tsx7 and generated an inline data block in the code which held (a) the number of arguments, and (b) the address of the calling procedure name, to make call trace easy. When I designed a language based on B, called IMP, it kept that particular part of the implementation. It was later running on GCOS, Varian620i, and Intel 8080 under both ISIS and CP/M. The procedure which returned the number of args was called nargs(). Where did that come from? I not only don't remember it in BCPL, I just looked through my manual and don't find it (at least in the index). If a portable varargs had been designed in at the start of the language it would have saved a lot of future problems. Even nargs() would help. I wonder if it was decided to leave it out of C, or if it by oversight just never got in. Better to have C where a few things didn't get in, than PL/1 or Ada, where everything got in. -- bill davidsen - sysop *IX BBS and Public Access UNIX davidsen@sixhub.uucp ...!uunet!crdgw1!sixhub!davidsen "Getting old is bad, but it beats the hell out of the alternative" -anon
henry@utzoo.uucp (Henry Spencer) (01/01/90)
In article <363@sixhub.UUCP> davidsen@sixhub.UUCP (bill davidsen) writes: >| Your function has to have some way of knowing how many arguments there >| are, or which is the last argument. >... If a portable varargs had been designed in at the start of the >language it would have saved a lot of future problems. Even nargs() >would help. I wonder if it was decided to leave it out of C, or if it >by oversight just never got in. Actually nargs() existed in early implementations, although it was always somewhat defective in that it reported the number of words of arguments rather than the number of arguments. (In BCPL the two numbers are always the same, but not in C.) It departed due to growing implementation difficulties. The fundamental problem with finding out how many arguments you have -- ignoring the problem of varying sizes, which got much worse when C acquired struct passing -- is that in general you need cooperation from the caller. On some machines, the information can be deduced from details of the stack frame or the calling sequence, but on many modern systems, it has to be explicitly provided at significant cost. Given the call-intensive nature of a lot of C programs, it is a seriously bad idea to incur such cost on every function call, given that most functions never need the information. Eventually there was enough demand for somebody at Bell Labs (Dennis?) to invent <varargs.h>. (No, like so many other things credited to Berkeley because they don't put credits in their manual pages, it was *not* invented at Berkeley. It existed in V7, although it was not documented.) X3J11 ended up fiddling with it a bit to make it more portable, but the facility finally does exist officially. However, you *still* need to have some way of figuring out how many arguments you've got -- the varargs stuff won't tell you. Given that it is now not kosher to use a varargs function without a prototype in scope, I suppose one could mandate a way to find out the size of the argument list, but the problem of differing sizes remains. -- 1972: Saturn V #15 flight-ready| Henry Spencer at U of Toronto Zoology 1989: birds nesting in engines | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
davidsen@sixhub.UUCP (Wm E. Davidsen Jr) (01/02/90)
In article <1990Jan1.004914.25006@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: | The fundamental problem with finding out how many arguments you have -- | ignoring the problem of varying sizes, which got much worse when C | acquired struct passing -- is that in general you need cooperation | from the caller. On some machines, the information can be deduced | from details of the stack frame or the calling sequence, but on many | modern systems, it has to be explicitly provided at significant cost. As I mentioned, the original versions which with I worked in the 70's did have the caller provide the information, but the cost was only one word in the call sequence (no CPU overhead). As common as calls are in C, they are a very small % of the code. Because of the size problems you mentioned, it is very difficult to deduce the number of arguments from the call frame, even when the size of the frame can be determined. Varargs is a workable solution to the problem, and I certainly don't suggest that there is a better simple one. Having to have both address and type information for the arguments certainly lends itself to cumbersome solutions. -- bill davidsen - sysop *IX BBS and Public Access UNIX davidsen@sixhub.uucp ...!uunet!crdgw1!sixhub!davidsen "Getting old is bad, but it beats the hell out of the alternative" -anon
henry@utzoo.uucp (Henry Spencer) (01/03/90)
In article <366@sixhub.UUCP> davidsen@sixhub.UUCP (bill davidsen) writes: >| ... On some machines, the information can be deduced >| from details of the stack frame or the calling sequence, but on many >| modern systems, it has to be explicitly provided at significant cost. > > As I mentioned, the original versions which with I worked in the 70's >did have the caller provide the information, but the cost was only one >word in the call sequence (no CPU overhead). As common as calls are in >C, they are a very small % of the code... They are not a small percentage of the time, however -- many C programs can spend a *lot* of time calling and returning if the sequences are inefficient. (There are C programs, I'm told, which spend 50% of their time in call/return on a VAX.) Reserving a word somewhere to hold the argument count is reasonable... but *where*? The code may not be readable at all (in fact, that was the reason why nargs() originally disappeared from C). Getting the value into data space, in general, takes run-time overhead on calls, and there is generally a considerable performance win in trimming every last unnecessary nanosecond out of calls. With ANSI C requiring prototypes to be in scope for varargs calls, there are now compilers that use different calling sequences for varargs and non-varargs functions. If everyone could be persuaded to do that, the efficiency argument would be largely moot: a bit of overhead in varargs calls, and *only* varargs calls, is not a problem (indeed, there is often considerable overhead there anyway). -- 1972: Saturn V #15 flight-ready| Henry Spencer at U of Toronto Zoology 1990: birds nesting in engines | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
econrad@thor.wright.edu (Eric Conrad) (01/03/90)
From article <1169@zip.eecs.umich.edu>, by bagchi@dip.eecs.umich.edu (Ranjan Bagchi): > > I'm working, currently, on a project that involves a function that > could take any number or arguments. I would like to pass it only > those arguments, i.e. no "flags" at the end which tell the function > to stop. If I understand the ANSI C mechanism, which uses varargs.h, you have to pass either some indication of the number of parameters or a sentinel parameter. I used this method once several months ago and found it a bit cumbersome. An alternative is to write a stack handling module and use it to push and pop parameters. The pop function could then return an stack empty status. The additional source code would be on the push side. -- Eric Conrad +----------------------------------------------------------+ | Eric Conrad - Wright State University | | "Progress was all right once, but it went on too long." | +----------------------------------------------------------+