mackenzi@agnes.uucp (David MacKenzie) (01/07/89)
The following program produces unexpected results: #include <varargs.h> main () { printf ("foo:\n"); foo (1, 2, 3, 0); printf ("bar:\n"); bar (4, 5, 6, 0); } foo (va_alist) va_dcl { bar (va_alist); } bar (va_alist) va_dcl { va_list list; int i; va_start (list); while (i = va_arg (list, int)) printf ("%d\n", i); va_end (list); } On a 68000 machine, it produces: foo: 1 14679744 160 1 2 3 bar: 4 5 6 and on a VAX it produces: foo: 1 bar: 4 5 6 whereas the output I wanted is: foo: 1 2 3 bar: 4 5 6 In other words, if I call bar () directly, it works, but if I call it via foo (), it breaks, in an implementation-dependant way, no less. Why? Is there anyway to get this to work? The problem has arisen as I am trying to port Allan Holub's (DDJ, April 1988) integer-only printf from <stdarg.h> to <varargs.h>. printf, sprintf, and fprintf are small little functions that call a function called idoprnt and both the small front-end functions and idoprnt seem to need to accept a variable number of arguments. David MacKenzie edf@rocky2.rockefeller.edu --- p.s. I post from this account because inews doesn't seem to be able to post new articles on rocky2 -- very strange, since it can post followups just fine.
gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/07/89)
In article <899@thor.stolaf.edu> edf@rocky2.rockefeller.edu writes: >The following program produces unexpected results: >foo (va_alist) > va_dcl >{ > bar (va_alist); >} No wonder! The only proper way to pass a variable argument list down another level is to pass an initialized va_list object. The bar() function cannot be called both with variable arguments AND with a single va_list argument. Check out the specs for vfprintf() and friends to see how this approach works.
ark@alice.UUCP (Andrew Koenig) (01/08/89)
In article <899@thor.stolaf.edu>, mackenzi@agnes.uucp (David MacKenzie) writes: > The following program produces unexpected results: > #include <varargs.h> > main () > { > printf ("foo:\n"); > foo (1, 2, 3, 0); > printf ("bar:\n"); > bar (4, 5, 6, 0); > } > foo (va_alist) > va_dcl > { > bar (va_alist); > } > bar (va_alist) > va_dcl > { > va_list list; > int i; > va_start (list); > while (i = va_arg (list, int)) > printf ("%d\n", i); > va_end (list); > } There is no way to pass your entire argument list to another function. The closest you can come is to pass a va_list. For example: main () { printf ("foo:\n"); foo (1, 2, 3, 0); } foo (va_alist) va_dcl { va_list list; va_start (list); bar (list); va_end (list); } bar (x) va_list x; { int i; while (i = va_arg (x, int)) printf ("%d\n", i); } -- --Andrew Koenig ark@europa.att.com
chris@mimsy.UUCP (Chris Torek) (01/08/89)
In article <899@thor.stolaf.edu> mackenzi@agnes.uucp (David MacKenzie) writes: >The following program produces unexpected results: >foo (va_alist) > va_dcl >{ > bar (va_alist); >} This program is quite thoroughly illegal. `va_alist' is allowed to be defined as a `magic token' that tells the compiler `I accept variable argument lists'; this magic token may well not be a valid argument. If you get lucky, the compiler will object to the call to bar(). >In other words, if I call bar () directly, it works, but if I call it via >foo (), it breaks, in an implementation-dependant way, no less. Why? Because indirect calls to bar() can never pass a variable argument list. >Is there anyway to get this to work? You cannot call bar() from foo() (except with a fixed argument list). What you CAN do is call a common routine from both foo() and bar(): foo(va_alist) va_dcl { va_list ap; va_start(ap); vbar(ap); va_end(ap); } bar(va_alist) va_dcl { va_list ap; va_start(ap); vbar(ap); va_end(ap); } vbar(ap) va_list ap; { ... code to deal with variable arguments ... } This is why vprintf, vfprintf, and vsprintf exist at all. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
chris@mimsy.UUCP (Chris Torek) (01/08/89)
In article <15341@mimsy.UUCP> I wrote: >... indirect calls to bar() can never pass a variable argument list. Oops, bad wording: *each* indirect call can pass a *different* fixed argument list, but any one given indirect call can only pass *one* fixed argument list. So indirect calls (plural) can, but an indirect call (singular) cannot. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
samperi@marob.MASA.COM (Dominick Samperi) (01/09/89)
In article <15341@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >[comments about System V style varargs usage...] It seems that for the ANSI style varargs (that is, the one requiring stdarg.h), at least one explicitly named arg must be included in the function definition, so that there is a FIRST that can be supplied to va_start, as in: va_list ap ; va_start(sp, FIRST) ; ... x = va_arg(ap, TYPE) ; ... va_end(ap) ; Is this correct? If not, how does one define a function with a variable number of args, for which there are no explicitly named args? The standard documentation on this (K&R Second Edition, for example) does not make this clear. It also seems to be the case that it is not possible for a called function (with a variable number of args) to determine how many args were actually passed, or when the last arg has been fetched, unless this information is supplied in the first parameter, say. Wouldn't it have been reasonable for the standard to specify that the compiler should enable the called function to determine the number of parameters that were passed, by automatically passing this information as a first implicit parameter, for example? Dominick Samperi samperi@acf8.nyu.edu uunet!hombre!samperi
chris@mimsy.UUCP (Chris Torek) (01/09/89)
In article <449@marob.MASA.COM> samperi@marob.MASA.COM (Dominick Samperi) writes: >It seems that for the ANSI style varargs (that is, the one requiring >stdarg.h), at least one explicitly named arg must be included in the >function definition [to provide an `anchor' for va_start] .... Correct. >... how does one define a function with a variable number of args, >for which there are no explicitly named args? I find it rather annoying that this is not possible. A routine like `make-vector', which takes a variable number of pointers and makes a vector of pointers (with the last signified by a NULL pointer of the appropriate type) must be written awkwardly instead of in the simple fashion possible with <varargs.h>. >Wouldn't it have been reasonable for the standard to specify that the >compiler should enable the called function to determine the number of >parameters that were passed ... ? Possibly. But that is not enough information: one needs not only the number of parameters, but also their types. It seems to me that doing half the job (providing the count without the types) would be worse than doing nothing at all. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
ark@alice.UUCP (Andrew Koenig) (01/09/89)
In article <449@marob.MASA.COM>, samperi@marob.MASA.COM (Dominick Samperi) writes: > In article <15341@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: > It seems that for the ANSI style varargs (that is, the one requiring > stdarg.h), at least one explicitly named arg must be included in the > function definition, so that there is a FIRST that can be supplied to > va_start, as in: > va_list ap ; > va_start(sp, FIRST) ; > x = va_arg(ap, TYPE) ; > va_end(ap) ; > Is this correct? Yes. > If not, how does one define a function with a variable > number of args, for which there are no explicitly named args? You can't. The rationale is that there is no reason ever to do so. After all, you have to know the type of the first argument somehow, and without looking at the argument list. > It also seems to be the case that it is not possible for a called function > (with a variable number of args) to determine how many args were actually > passed, or when the last arg has been fetched, unless this information is > supplied in the first parameter, say. Correct. > Wouldn't it have been reasonable for > the standard to specify that the compiler should enable the called function > to determine the number of parameters that were passed, by automatically > passing this information as a first implicit parameter, for example? Sure, but they didn't do it that way. For one thing, that would slow down every call a little. -- --Andrew Koenig ark@europa.att.com
gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/09/89)
In article <449@marob.MASA.COM> samperi@marob.masa.com (Dominick Samperi) writes: >It seems that for the ANSI style varargs (that is, the one requiring >stdarg.h), at least one explicitly named arg must be included in the >function definition, so that there is a FIRST that can be supplied to >va_start, ... Is this correct? Yes. Some implementors claimed that this "hook" was necessary in order for their <stdarg.h> implementation to have a reference point for va_arg to use. I think actually with certain compiler trickery this could have been made invisible to the programmer, but the Committee was willing to require the "anchor" argument(s) to be present. I've been programming variable-argument functions with code for both __STDC__ and old UNIX C for quite some time now, and this constraint hasn't been much of a problem. >It also seems to be the case that it is not possible for a called function >(with a variable number of args) to determine how many args were actually >passed, or when the last arg has been fetched, unless this information is >supplied in the first parameter, say. Yup. This reflects existing C practice. PDP-11 UNIX had an nargs() function that purported to return the argument count, but it didn't work right (it returned the number of words of arguments, not the count). Making this work right would have slowed down every function call. nargs() was practically unused... >Wouldn't it have been reasonable for the standard to specify that the >compiler should enable the called function to determine the number of >parameters that were passed, by automatically passing this information >as a first implicit parameter, for example? Why burden all implementations all the time when you can provide this yourself as a patent argument in those cases where you need it? You could also use a "sentinel" argument, e.g. concat(dest,"str_a","str_b","str_c",(char*)0);
ka@june.cs.washington.edu (Kenneth Almquist) (01/09/89)
Chris Torek gives some code for the situation in which one routine with a variable number of arguments wants to have these arguments interpreted by a different routine. (See the end of this article.) I've used the same approach for lack of anything better, but is it portable? The manual page for varargs doesn't say anything about the effects of passing the va_list variable to another routine. The vprintf family of routines are defined to accept va_list arguments, which should encourage implementors to make this work, but doesn't force them to. (They could have vprintf perform some special operations to simulate the environment of its caller before using va_arg.) Perhaps the definition of the stdarg mechanism is more specific? Also, I'm curious about why Ansi C uses the stdarg mechanism instead of varargs. I would think that varargs would be easier to implement. On machines with simple calling conventions varargs requires no compiler support; on other machines varargs is likely to require fewer special cases than stdarg since either all or none of the arguments are handled by the varargs mechanism. Kenneth Almquist bar(va_alist) va_dcl { va_list ap; va_start(ap); vbar(ap); va_end(ap); } vbar(ap) va_list ap; { ... code to deal with variable arguments ... ... [uses va_arg(ap, type) to access arguments to "bar"] ... }
gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/09/89)
In article <6898@june.cs.washington.edu> ka@june.cs.washington.edu (Kenneth Almquist) writes: >The manual page for varargs doesn't say anything about the effects of >passing the va_list variable to another routine. The varargs documentation left a lot unspecified, and consequently some implementations indeed will not do the expected thing when you try to pass a va_list to a subfunction. However, such implementations need to fix this anyway for their stdarg (ANSI C) version, and probably at the same time their varargs macros can be fixed. Many vendors already have done so, motivated perhaps more by SVID compliance than anything else. >Perhaps the definition of the stdarg mechanism is more specific? Definitely. >Also, I'm curious about why Ansi C uses the stdarg mechanism instead of >varargs. I would think that varargs would be easier to implement. To the contrary, on some architectures <varargs.h> was much harder to implement than <stdarg.h>. I collected input from many C implementors on behalf of X3J11, and had extended discussions about variable arguments with several. I believe <stdarg.h> is reasonable.
karl@haddock.ima.isc.com (Karl Heuer) (01/10/89)
I actually (slightly reluctantly) agree that it's not worthwhile to provide nargs() or equivalent, but allow me to play Devil's Advocate for a bit... In article <9317@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes: >In article <449@marob.MASA.COM> samperi@marob.masa.com (Dominick Samperi) writes: >>It also seems to be the case that it is not possible for a called function >>(with a variable number of args) to determine how many args were actually >>passed, or when the last arg has been fetched, unless this information is >>supplied in the first parameter, say. > >Yup. This reflects existing C practice. PDP-11 UNIX had an nargs() >function that purported to return the argument count, but it didn't >work right (it returned the number of words of arguments, not the count). >Making this work right would have slowed down every function call. Only calls to variadic functions; fixed-argument functions don't need the feature, and it needn't be supplied for them. (An ANSI compiler can tell whether a function is variadic.) Moreover, since it removes the need for a sentinel on such functions as execl(), the cost of adding it as a pseudo- argument should be offset by the benefit of removing the sentinel. (And on some implementations, the cost is already zero, so the benefit would be picked up for free.) (Lest someone feel the need to point this out: the major problem is that execl() is already frozen; also, the printf() family doesn't pick up the benefit, since there's no sentinel.) >>Wouldn't it have been reasonable for the standard to specify [nargs]? > >Why burden all implementations all the time when you can provide this >yourself as a patent argument in those cases where you need it? Because computers are much better at counting things than humans are. If some of the arguments are ifdef'd out, getting the count right can be hairy. >You could also use a "sentinel" argument, e.g. > concat(dest,"str_a","str_b","str_c",(char*)0); This works as long as the arg type is something with an out-of-band value, but it doesn't help if you want to write a function min(int, ...). Chris Torek wrote: >Possibly. But that is not enough information: one needs not only the >number of parameters, but also their types. It seems to me that doing >half the job (providing the count without the types) would be worse than >doing nothing at all. Yes, it does seem as though nargs() is not very useful for polymorphic functions. (And, as Doug pointed out, the number-of-words implementation is bad--though this could be fixed by having nargs() return the number of bytes so that the application could say nb -= sizeof(TYPE), assuming it knows what type to expect next.) Perhaps what we need is a separate type of declaration syntax for variadic, automatically-argcounted, monomorphic functions; then only those functions that use this new declaration would pay the price, if any, associated with making the information available. Fix it in `D'... Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
guy@auspex.UUCP (Guy Harris) (01/10/89)
>> Wouldn't it have been reasonable for >> the standard to specify that the compiler should enable the called function >> to determine the number of parameters that were passed, by automatically >> passing this information as a first implicit parameter, for example? > ... >For one thing, that would slow down every call a little. To be fair, it wouldn't have to slow *every* call down, just calls to functions for which a prototype is in scope that specifies that it is a varargs function....
gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/10/89)
In article <11378@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: >Yes, it does seem as though nargs() is not very useful for polymorphic >functions. (And, as Doug pointed out, the number-of-words implementation is >bad--though this could be fixed by having nargs() return the number of bytes >so that the application could say nb -= sizeof(TYPE), assuming it knows what >type to expect next.) No, if nargs() has any use at all it cannot be this. The reason that the va_ stuff must be used for portable access to arguments is that many architectures do not have a simple, clean model for argument alignment (which might be different from that indicated by sizeof), and some pass some of the arguments different from others. nbytes() would be of no value in portable programming.
scs@adam.pika.mit.edu (Steve Summit) (01/10/89)
In article <8699@alice.UUCP> ark@alice.UUCP (Andrew Koenig) writes: >There is no way to pass your entire argument list to another function. Well, no socially acceptable way, maybe, but in the words of Romeo Void, "Never say 'Never'." I've got a routine called "callg," named after the VAX instruction of the same name, which lets you call an arbitrary function with an arbitrary number of arguments. It's sort of an inverse varargs. Among other things, I have used it to solve exactly the problem being discussed here, namely to call a varargs function from a varargs function, explicitly passing all of the first varargs function's arguments, rather than indirectly through a va_list. callg is actually implemented such that its invocation is (well, could be, I haven't tried it everywhere) portable, although the underlying implementation is obviously highly machine dependent. (It's one of a handful of functions I know of that can't possibly be written in C.) Steve Summit scs@adam.pika.mit.edu
friedl@vsi.COM (Stephen J. Friedl) (01/11/89)
In article <9321@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes: > > The reason that > the va_ stuff must be used for portable access to arguments is that > many architectures do not have a simple, clean model for argument > alignment (which might be different from that indicated by sizeof), > and some pass some of the arguments different from others. Doug is being polite here -- there are some *very* crazy arg-passing schemes out there. The Zilog Z8000 machine I used in school had an "efficient" arg passing mechanism that passed the first few args in registers. There were six or so 16-bit registers allocated for this, and 32-bit quantities passed in register pairs R0+R1 = RR0, R2+R3=RR2, etc. There were all kinds of rules for alignment restrictions on this, *PLUS* the machine had a segmented and a non-segmented mode which meant that pointers could be two different lengths. If they had varargs (it was Sys III), it must have been hell to put together. I do know that their _doprnt() had *five* args to accomodate this. I remember a time several years ago in school that I naively claimed that taking the address of an arg and (*argp++) up the stack was portable because "everybody passes args this way". The amazing follies of youth :-). Steve -- Stephen J. Friedl 3B2-kind-of-guy friedl@vsi.com V-Systems, Inc. I speak for me only attmail!vsi!friedl Santa Ana, CA USA +1 714 545 6442 {backbones}!vsi!friedl -------Nancy Reagan on Usenix in San Diego: "Just say *go*"-------
seanf@sco.COM (Sean Fagan) (01/11/89)
>> Wouldn't it have been reasonable for >> the standard to specify that the compiler should enable the called function >> to determine the number of parameters that were passed, by automatically >> passing this information as a first implicit parameter, for example? >For one thing, that would slow down every call a little. Some machines (VAXen and WE32100's) already do this. It doesn't slow the call down, since it's always there. However, it could be argued that the call could have been made faster by not wasting microcode space... -- Sean Eric Fagan | "Joy is in the ears that hear, not in the mouth that speaks." seanf@sco.UUCP | -- Saltheart Foamfollower (Stephen R. Donaldson) (408) 458-1422 | Any opinions expressed are my own, not my employers'.
guy@auspex.UUCP (Guy Harris) (01/12/89)
>It doesn't slow the call down, since it's always there. However, it could >be argued that the call could have been made faster by not wasting microcode >space... Or by not wasting memory and CPU cycles fetching the count from the instruction stream and stuffing it onto the stack.
ftw@masscomp.UUCP (Farrell Woods) (01/13/89)
In article <1002@vsi.COM> friedl@vsi.COM (Stephen J. Friedl) writes: > >The Zilog Z8000 machine I used in school had an "efficient" >arg passing mechanism that passed the first few args in >registers. Some C compilers for more "conventional" machines also pass arguments this way. For instance, the Microware C compiler for their OS-9/68K operating system will usually pass the first couple of args in d0 and d1, and the rest on the stack. Made for an interesting varargs... -- Farrell T. Woods Voice: (508) 692-6200 x2471 MASSCOMP Operating Systems Group Internet: ftw@masscomp.com 1 Technology Way uucp: {backbones}!masscomp!ftw Westford, MA 01886 OS/2: Half an operating system
karl@haddock.ima.isc.com (Karl Heuer) (01/13/89)
In article <9321@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes: >In article <11378@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: >>[returning the total number of varargs bytes might be useful] > >No, if nargs() has any use at all it cannot be this. The reason that >the va_ stuff must be used for portable access to arguments is that >many architectures do not have a simple, clean model for argument >alignment (which might be different from that indicated by sizeof), >and some pass some of the arguments different from others. nbytes() >would be of no value in portable programming. I don't see any problem. The proposal is that the variadic function knows the sum of the sizes of the (widened) arguments in the nonfixed portion of the arglist; given this information, the code nb = va_nbytes(); while (format_indicates_another_arg) { if (char_expected) { nb -= sizeof(int); ch = (char)va_arg(ap, int); do_char(ch); } else if (long_expected) { nb -= sizeof(long); ii = va_arg(ap, int); do_long(ii); } } is portable. (To be useful, add appropriate checks on the value of nb.) If the calling convention is such that the callee can compute the byte count, then everything is okay. If not, then the caller (which can easily compute it) can supply it via a hidden argument. It doesn't matter how kludgy the argument passing mechanism is. I'm not trying to claim that this would solve all of the problems with variadic functions; this is just to demonstrate that it's not necessarily fatal that the pdp11 nargs() can't count actual arguments. Either a true arg count or a byte count could plausibly be standardized (the caller knows both), but on some implementations the byte count is already available without an extra hook. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/13/89)
In article <11410@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: >... given this information, the code ... is portable. No it isn't!! Apart from the obvious slip of picking up an int where a long was required (which can be fixed), your use of sizeof to adjust the byte count is flawed, because sizeof doesn't take into account alignment requirements of the arguments, which can (and sometimes do) differ from those of array members. To make this work portably, you would have to require implementations to provide at least one more va_ function, but what's the point? By that time, the postulated utility of an argument byte count has been lost under a barrage of details. By the way, the alternate idea of casting argument addresses to (char *) then subtracting them to count bytes fails due to not knowing in advance what the type of the next argument is. There may be room for another argument of one type, but not of another type, and unless you know more than byte counts you cannot determine whether or not to pick up another argument.
dff@Morgan.COM (Daniel F. Fisher) (01/14/89)
In article <11410@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) proposes a va_nbytes() to be used in implementing portable argument counting. In article <9358@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) indicates that such a construct is not portable because use of sizeof to adjust the argument byte count is flawed, due to the alignment differences for array members and normal parameters. Since arrays cannot be passed by value in C, I fail to see how this is relevant. However, I do agree with the conclusion, since one can postulate calling sequences that are not strictly stack based. Particularly in an interpreted environment or a massively parallel architecture. In evaluating proposals for a portable nargs() like mechanism, it is necessary to keep in mind the purpose this mechanism. If, on the one hand, the nargs() mechanism is to be used by functions so that they do not have to rely on sentinel arguments or information implicit in a required argument to determine how many arguments they have, then a portable nargs() like mechanism is clearly required. _IF_ this is the purpose, I would propose a macro, va_nargs(parg, type), that evaluates to the number of arguments of the given type remaining. By this, I do NOT mean to suggest that the calling sequence has to identify the type of every argument. All that is required, is that the va_nargs() macro indicate how many successive va_arg(parg, type) invocations would succeed given the current state of argument processing. But, if this _IS_ the purpose, I believe that these varargs functions should require the caller to provide the argument count explicitly as one of the required arguments, instead of burdening the calling sequence with this overhead on EVERY function call to ANY function. If, on the other hand, the nargs() mechanism is to be used as a run-time sanity check for adherence to a varargs calling convention making use of a sentinel argument or relying on information present in some required argument, then what is required is an assert() like mechanism. I would propose that the va_arg() macro be modified to allow it to abort the program if it cannot return an argument of the indicated type. If the normal calling sequence does not provide argument count information, then it would need to be augmented as appropriate. Since the new calling sequence and run time checking in va_arg() might be too time consuming, their use would need to be controlled by a compile time switch of some type. Perhaps "#ifndef NDEBUG" as is used by assert(). While this is easy to do when selecting which form of the va_arg() macro to use, it presents an interesting challenge in designing calling sequences. The basic problem is how to make the normal and augmented calling sequences compatible. (Incompatible calling sequences, would be a pain in the head.) I am not sure how to achieve compatibility without making the normal calling sequence as inefficient as the augmented calling sequence. Calling Sequence Compatibility If a function using the augmented calling sequence calls one expecting the normal calling sequence, how does the called function ignore argument count information? If a function using the normal calling sequence calls on using the augmented supporting calling sequence, how does the called function process the arguments correctly and avoid any argument count checking in va_arg()? The answers may be non-trivial. If the argument count information is at the end of the argument list, it cannot be located when it is needed. If the argument count information is at the beginning of the argument list, then it cannot be distinguished from the first argument. If the argument count information is elsewhere in the argument list, then there is a combination of these difficulties. So the argument count information would need to be kept somewhere else. If it is a register, then both calling sequences would need to set it to some meaningful value. If it is in a reserved place on the stack, the same is true. What to do? What to do? N.B.: By argument count information in the above, I refer to that information required by va_arg() to determine if it is valid to return an argument of the requested type. The precise form this takes would be an implementation issue. Implementation in a 3B2 like environment is straight forward, because the %AP (argument pointer) and %FP (frame pointer) registers will bound the argument list in known way. Implementation in a 68020 like environment probably requires that an argument pointer or argument count be pushed as the last argument in all function calls. More exotic calling sequences might require information about the type of each argument. -- Daniel F. Fisher dff@morgan.com
karl@haddock.ima.isc.com (Karl Heuer) (01/14/89)
In article <9358@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes: >In article <11410@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: >>... given this information, the code ... is portable. > >No it isn't!! ... your use of sizeof to adjust the byte count is flawed, >because sizeof doesn't take into account alignment requirements of the >arguments, which can (and sometimes do) differ from those of array members. I'm assuming that va_nbytes() would be *defined* to return sum(each undeclared argument a)(sizeof(a)), rather than the amount of space used on the stack. On implementations where these agree, there may be a fast way to compute the value from the callee. On implementations with the strange alignment requirements, or where other problems prevent the callee from doing this, the compiler would have to provide the information at the caller's end. Actually, both va_nbytes() and va_nargs() are more powerful than necessary. Typically, all the user wants to know is whether or not there is another argument available for fetching with va_arg(), so a boolean va_isarg() would suffice. Any implementation on which it is currently possible to write either va_nbytes() or va_nargs() correctly could add va_isarg() in such a way that there is no cost associated with it in programs that don't use it. (There are implementations in which none of these three can be written without passing hints from the caller, which is probably the main reason why this isn't worth standardizing.) Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/15/89)
In article <202@mstan.Morgan.COM> dff@Morgan.COM (Daniel F. Fisher) writes: >Since arrays cannot be passed by value in C, I fail to see how this >is relevant. I wasn't talking about array ARGUMENTS. sizeof returns the size of an object when used as a member of an array. This is not necessarily the same as the number of bytes needed when used as an argument, due to possibly different alignment requirements in the two cases. In fact, some arguments in some implementations are passed in fast registers! >What to do? What to do? Not to worry about va_nargs(). It's not useful enough to be worth the hassle.
dff@Morgan.COM (Daniel F. Fisher) (01/15/89)
In article <9381@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn ) writes: >In article <202@mstan.Morgan.COM> dff@Morgan.COM (Daniel F. Fisher) writes: >>Since arrays cannot be passed by value in C, I fail to see how this >>is relevant. > > . . . sizeof returns the size of an >object when used as a member of an array. . . . I see Mr. Gwyn's point, and I believe it is relevant. >>What to do? What to do? > >Not to worry about va_nargs(). It's not useful enough to be worth >the hassle. That is the opinion I expressed in my earlier posting. I indicated that while a va_nargs(parg, type) macro is portable way for functions to count their arguments, I felt that this would be wasteful, given that other means were available, such as rewriting a function that uses va_nargs() so that it takes its argument count as an argument. My "What to do? What to do?" followed a discussion of how to implement va_arg() in such away that when NDEBUG was not defined it would cause the program to abort() if there were no remaining arguments of the requested type. What I couldn't figure out was how to implement this facility so it did not beget the same overhead as that which is inherent in va_nargs(). Specifically, I was wondering how to construct a calling sequence that was ambivalent to the presence of argument count information but which would allow the callee to ascertain the presence of this information. Perhaps a va_arg() macro that aborts if it does not have an argument is also not worth the hassle. Particularly if it requires the same additional overhead in all function calls as va_nargs() appears to require. But I do believe it is MORE of a hassle than va_nargs(). In article <11428@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes on the same subject: >Actually, both va_nbytes() and va_nargs() are more powerful than necessary. >Typically, all the user wants to know is whether or not there is another >argument available for fetching with va_arg(), so a boolean va_isarg() would >suffice. I considered suggesting va_isarg() when preparing my earlier posting, but concluded that it is not appropriate, since the unavailability of a necessary argument represents a programming error which is best treated as an assertion failure. This is what led me to suggest that va_arg abort if it cannot return an argument of the requested type. I can see, however, that a more general form of assert() might invoke an exception handler, so I wish to modify my earlier descriptions of the "bullet-proof" va_arg() to be "like the usual va_arg() except that, prior to returning the argument, it asserts that it can and allows assert() to take the usual action if the assertion fails." -- Daniel F. Fisher dff@morgan.com
karl@haddock.ima.isc.com (Karl Heuer) (01/27/89)
In article <203@s5.Morgan.COM> dff@Morgan.COM (Daniel F. Fisher) writes: >In article <11428@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) >[suggests that for most purposes] a boolean va_isarg() would suffice. > >I considered [that], but concluded that it is not appropriate, since the >unavailability of a necessary argument represents a programming error which >is best treated as an assertion failure. Here's a counterexample. int min(int first, ...) { int i; va_list ap; va_start(ap, first); while (va_isarg(ap)) { if ((i = va_arg(ap, int)) < first) first = i; } return (first); } This function, which cannot be written in either pre-ANSI or ANSI C, uses va_isarg() to obviate the need for an explicit extra argument. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
dyoung@media-lab.MEDIA.MIT.EDU (David Young) (02/12/91)
I'd like to be able to write a macro or a function that will take an
unspecified number of arguments -- similar to how the printf() function
works. What I'd like is something that could transform a call like:
PringMsg( window, formatString, <formatArgs>)
into the following chunk of code:
{
sprintf( globalFoo, formatString, <formatArgs>);
BlahBlah( window, globalFoo);
}
I was hoping to find something similar to the &rest capability of Lisp.
But am scared I'll have to end up using vprintf().
Can anyone help or offer a suggestion or solution?
Thanks,
david young
jik@athena.mit.edu (Jonathan I. Kamens) (02/12/91)
If you're using an ANSI C compiler that has <stdarg.h>, then see the documentation in K&R 2 (and whatever books you have that talk about ANSI C) that talks about variable-argument functions. If you're not, and your system has <varargs.h>, then see the man page for varargs for information about how to do variable-argument functions. In fact, you probably *are* going to end up using vprintf rather than being able to call sprintf and convince it that some of youre function's arguments are the arguments that it should use. But that isn't such a big deal if you have vprintf. If you don't there are public domain implementations of it all over the place, including one in comp.sources.misc or comp.sources.unix (I forget which). I've found that a good place to see how variable argument stuff works with <varargs.h> is the source code for GNU awk. -- Jonathan Kamens USnail: MIT Project Athena 11 Ashford Terrace jik@Athena.MIT.EDU Allston, MA 02134 Office: 617-253-8085 Home: 617-782-0710
henry@zoo.toronto.edu (Henry Spencer) (02/12/91)
In article <5196@media-lab.MEDIA.MIT.EDU> dyoung@media-lab.media.mit.edu.UUCP (David Young) writes: >I'd like to be able to write a macro or a function that will take an >unspecified number of arguments... For a function, you'll need to use <stdarg.h> (ANSI C) or <varargs.h> (many old implementations). Can't be done with a macro at all. -- "Read the OSI protocol specifications? | Henry Spencer @ U of Toronto Zoology I can't even *lift* them!" | henry@zoo.toronto.edu utzoo!henry
sanders@peyote.cactus.org (Tony Sanders) (02/12/91)
In article <1991Feb11.225815.5875@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: >For a function, you'll need to use <stdarg.h> (ANSI C) or <varargs.h> (many >old implementations). Can't be done with a macro at all. This is annoying. How do get around this problem so I can easily eliminate debug code if NODEBUG is set (or if DEBUG isn't set, whichever). For instance... This works great: #ifdef NODEBUG #define DPV(var,type) /* Removes code like magic */ #else #define DPV(var,type) fprintf(stderr,"%s:%d, " # var " = %" # type "\n",var); #endif But I can't do this: #ifdef NODEBUG #define DP(fmt,...) /* sigh */ #else #define DP(fmt,...) fprintf(stderr,fmt,...); #endif So I do this: #ifdef NODEBUG #define DP(level) if (0) /* I hope the optimizer gets rid of this */ #else extern DebugPrint(char *,...); #define DP(level) if (debug&level) DebugPrint #endif DP(1)("this fmt string %s\n","sucks rocks"); Any better ideas??? -- sanders@peyote.cactus.org First rule of software: Throw the first one away. and so on... I am not an IBM representative and I speak only for myself.
gerrit@xelion.UUCP (Gerrit Brouwer) (02/13/91)
sanders@peyote.cactus.org (Tony Sanders) writes: >In article <1991Feb11.225815.5875@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: >So I do this: >#ifdef NODEBUG >#define DP(level) if (0) /* I hope the optimizer gets rid of this */ >#else >extern DebugPrint(char *,...); >#define DP(level) if (debug&level) DebugPrint >#endif >DP(1)("this fmt string %s\n","sucks rocks"); >Any better ideas??? I do this: #ifdef DO_DEBUG #define PRINT(ARGUMENTS) DebugPrint ARGUMENTS #else #define PRINT(ARGUMENTS) DebugPrint ARGUMENTS #endif DO_DEBUG PRINT(("any number of arguments allowed: %s %d %f\n", "string", 4, 3.14)); -- Gerrit Brouwer domain : gerrit@xelion.UUCP XELION BV uucp : uunet!mcsun!hp4nl!xelion!gerrit Postbus 88 phone : +31 15 622121 2600 AB Delft, The Netherlands fax : +31 15 621760
dave@aspect.UUCP (Dave Corcoran) (02/14/91)
In article <5196@media-lab.MEDIA.MIT.EDU>, dyoung@media-lab.MEDIA.MIT.EDU (David Young) writes: > > What I'd like is something that could transform a call like: > > PringMsg( window, formatString, <formatArgs>) > > into the following chunk of code: > > { > sprintf( globalFoo, formatString, <formatArgs>); > BlahBlah( window, globalFoo); > } > run this through m4 --------------------8<-------------------------- define(PringMsg,` { sprintf(globalFoo, $2, shift(shift($*))); BlahBlah($1, globalFoo); }') PringMsg( window, formatString, f,o,rm,at,Ar,gs) PringMsg( window, formatString, form,at,Args) --------------------8<-------------------------- CAVEAT: you cannot have commas in formatString -- David Corcoran -@@ uunet!aspect!dave ~ In a society where anything goes eventually everything will.
dave@aspect.UUCP (Dave Corcoran) (02/14/91)
In article <5270@awdprime.UUCP>, sanders@peyote.cactus.org (Tony Sanders) writes: > But I can't do this: > #ifdef NODEBUG > #define DP(fmt,...) /* sigh */ > #else > #define DP(fmt,...) fprintf(stderr,fmt,...); > #endif > > Any better ideas??? yet another posible m4 solution: ------------------8<---------------------------- define(DBP,`ifdef(`DEBUG',fprintf(stderr,$*))') DBP("not printed %d",1); ^ unfortunately this "gets through" in both cases define(`DEBUG') DBP("printed %d%d%d",1,23,4); DBP("so is this %s\n","string"); ------------------8<---------------------------- -- David Corcoran -@@ uunet!aspect!dave ~ In a society where anything goes eventually everything will.
torek@elf.ee.lbl.gov (Chris Torek) (02/14/91)
In article <5196@media-lab.MEDIA.MIT.EDU> dyoung@media-lab.media.mit.edu.UUCP (David Young) writes: >What I'd like is something that could transform a call like: > > PringMsg( window, formatString, <formatArgs>) > >into the following chunk of code: > > { > sprintf( globalFoo, formatString, <formatArgs>); > BlahBlah( window, globalFoo); > } The following is the only current approach that is anywhere near portable: #define SIZE 1024 /* and pray */ #if __STDC__ void PrintMsg(WINDOW *window, char *fmt, ...) { va_list ap; char buf[SIZE]; va_start(ap, fmt); (void) vsprintf(buf, fmt, ap); va_end(ap); BlahBlah(window, buf); } #else void PrintMsg(va_alist) va_dcl { WINDOW *window; char *fmt; va_list ap; char buf[SIZE]; va_start(ap); window = va_arg(ap, WINDOW *); fmt = va_arg(ap, char *); (void) vsprintf(buf, fmt, ap); va_end(ap); BlahBlah(window, buf); } #endif (Something very much like this, but with a size of 2048, appears in the X11 sources.) This method is not terribly satisfactory. The size sets an upper bound on the amount that can be printed in one call. Worse, if the format plus arguments produce more than SIZE-1 characters, vsprintf silently overruns the buffer, typically causing some kind of catastrophic error soon afterward. The latest Berkeley system (i.e., the one you cannot get yet) has two new facilities in the C library that improve on this. The first is the pair of functions `snprintf' and `vsnprintf', which take a buffer size. They return the number of characters required to hold the entire output. Thus: /* declarations and beginning as before, but add `char *cp;' and `int ret;' */ ret = vsnprintf(buf, sizeof buf, fmt, ap); if (ret < sizeof buf) { /* everything was printed; the buffer is fine */ cp = buf; goto done; /* XXX `goto' is required on Pyramid */ } /* some of the text was truncated */ va_end(ap); /* this macro may include an unbalanced } */ cp = malloc(ret + 1); if (cp == NULL) die("out of memory"); va_start(ap); window = va_arg(ap, WINDOW *); fmt = va_arg(ap, char *); (void) vsnprintf(cp, ret + 1, fmt, ap); done: va_end(ap); BlahBlah(cp); if (cp != buf) free(cp); The second facility, and the one that is preferred for this sort of thing, is the ability to open your own I/O functions. In this case the desired function is the equivalent of the `write' system call, and it needs one pointer parameter, which happens to be exactly what the interface provides (in the shape of a `void *'): /* __STDC__ assumed here */ static int aux_write(void *cookie, const char *buf, int nbytes) { WINDOW *w = cookie; window_write(w, buf, nbytes); return nbytes; } int PrintMsg(WINDOW *w, const char *fmt, ...) { FILE *fp; va_list ap; fp = fwopen(w, aux_write); if (fp == NULL) die("out of memory, or something equally bad"); va_start(ap, fmt); (void) vfprintf(fp, fmt, ap); va_end(ap); (void) fclose(fp); } This allows an arbitrarily large amount of data to move between the caller and the window, passing through an arbitrarily small pipe (the stdio buffer attached to the file `fp'). The only requirement here is that user I/O functions act like read() and write() (and, if seek and close are provided, lseek() and close()). -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab EE div (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov
catfood@NCoast.ORG (Mark W. Schumann) (02/17/91)
In article <5196@media-lab.MEDIA.MIT.EDU> dyoung@media-lab.media.mit.edu.UUCP (David Young) writes: >I'd like to be able to write a macro or a function that will take an >unspecified number of arguments -- similar to how the printf() function >works. What I'd like is something that could transform a call like: > > PringMsg( window, formatString, <formatArgs>) > >into the following chunk of code: > > { > sprintf( globalFoo, formatString, <formatArgs>); > BlahBlah( window, globalFoo); > } > >I was hoping to find something similar to the &rest capability of Lisp. >But am scared I'll have to end up using vprintf(). > >Can anyone help or offer a suggestion or solution? vsprintf() is part of ANSI C according to my Turbo manual. ^^^^^^^^ -- ============================================================ Mark W. Schumann 3111 Mapledale Avenue, Cleveland 44109 USA Domain: catfood@ncoast.org UUCP: ...!mailrus!usenet.ins.cwru.edu!ncoast!catfood