daveh@marob.MASA.COM (Dave Hammond) (01/20/89)
Two [semi-related] questions, first:
Given B() which expects 3 arguments passed to it, it's reasonably
obvious what can occur when A() invokes B() and passes less than 3 args.
What potential problems exist if A() passes *more* than 3 args to B()?
It seems to me that this would harm nothing, since the extra stuff
ends up beyond the current stack position.
Second:
I was surprised to see the following in a "GNU-something" source file:
lprintf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,10)
char *fmt;
{
char buf[BUFSIZ];
sprintf(buf,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,10)
...
}
Given the availability of varargs, is this style still acceptable and,
more importantly, is it portable?
--
Dave Hammond
...!uunet!masa.com!{marob,dsix2}!daveh
gwyn@smoke.BRL.MIL (Doug Gwyn ) (01/21/89)
In article <470@marob.MASA.COM> daveh@marob.masa.com (Dave Hammond) writes: >What potential problems exist if A() passes *more* than 3 args to B()? >It seems to me that this would harm nothing, since the extra stuff >ends up beyond the current stack position. Stack? What stack? The C language doesn't say anything about a stack. In fact there are reasonable implementations that (a) pass arguments differently for different parameter types (b) use different mechanisms for passing different numbers of arguments. >I was surprised to see the following in a "GNU-something" source file: >lprintf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,10) >char *fmt; >{ > char buf[BUFSIZ]; > sprintf(buf,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,10) >} >Given the availability of varargs, is this style still acceptable and, >more importantly, is it portable? That style never WAS acceptable; it relies on implementation-dependent kludgery and will not work on some implementations. Before there was <varargs.h>, this technique was resorted to fairly heavily because it happened to work (most of the time) on the local implementation and there was no better recourse. The proper way to do this is with <varargs.h> or <stdarg.h> macros, passing the va_list to vsprintf(). Of course, some systems don't have vsprintf(), but the solution there is to implement vsprintf() (it's just a few lines of code) and add it to the local set of C library extensions.
henry@utzoo.uucp (Henry Spencer) (01/22/89)
In article <470@marob.MASA.COM> daveh@marob.masa.com (Dave Hammond) writes: >Given B() which expects 3 arguments passed to it, it's reasonably >obvious what can occur when A() invokes B() and passes less than 3 args. Oh really? In a particular implementation, maybe. Not in general. About the only general prediction which can be made (which is probably what Dave was thinking of) is "trouble". >What potential problems exist if A() passes *more* than 3 args to B()? >It seems to me that this would harm nothing, since the extra stuff >ends up beyond the current stack position. Stack? What's that? And why do you assume that extras end up on the tail end? They could just as easily end up on the front. The only general statement that can be made is "possible trouble". You can get away with it in some implementations, including many of the early C implementations... but not all. >lprintf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,10) >char *fmt; >{ > char buf[BUFSIZ]; > sprintf(buf,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,10) > ... >} > >Given the availability of varargs, is this style still acceptable and, >more importantly, is it portable? It has never been portable. Whether it is acceptable, or has ever been acceptable, depends on who you ask; the answers at utzoo are "no" and "no". -- Allegedly heard aboard Mir: "A | Henry Spencer at U of Toronto Zoology toast to comrade Van Allen!!" | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
ge@phoibos.UUCP (Ge Weijers) (01/23/89)
In article <470@marob.MASA.COM>, daveh@marob.MASA.COM (Dave Hammond) writes: > I was surprised to see the following in a "GNU-something" source file: > > lprintf(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,10) > char *fmt; > { > char buf[BUFSIZ]; > sprintf(buf,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,10) > ... > } > > Given the availability of varargs, is this style still acceptable and, > more importantly, is it portable? > > -- > Dave Hammond > ...!uunet!masa.com!{marob,dsix2}!daveh This is NOT portable. Some compilers use strange calling conventions which will cause this example to break. An example: The Turbo C compiler for the Atari ST (sold in Europe) uses registers to pass arguments. The calling convention is the following (except for details, I'm producing this from memory): The first 3 scalar (int, long, char etc.) variables are passed in registers D0-D2, and the first 2 pointer variables in A0-A1. The call f(3,&var) and f(&var,3) will yield the same code. The above example breaks. It is possible to use the ANSI <stdarg.h> variable argument passing, because the compiler does not pass arguments in registers that correspond to the ... in an ANSI prototype (line lprintf(char *format, ...)) You'd be better off using <varargs.h> or <stdarg.h>, then it is at least obvious where you have to change a program.