pete@tutor.UUCP (Peter Schmitt) (10/20/88)
I want to write a function that accepts a variable number of string arguments. What is a possible way to do this? -pete -- \\\!/// Peter Schmitt _ _ UUCP: decwrl!tsc.dnet!tutor!pete ( Q Q ) .or. att!tsc!tutor!pete ---,,,,-------U-------,,,,--- ARPA: tutor!pete%tsc.dec.com@decwrl.dec.com
burris@ihuxz.ATT.COM (Burris) (10/21/88)
> I want to write a function that accepts a variable number of string > arguments. What is a possible way to do this? > > -pete > In the C language arguments are placed on the stack in reverse order such that the first argument is the lowest index off of the stack pointer. This allows you to pass the first argument as a count of the number of following arguments. Example: string_func( 3, "how", "what", "why" ); or string_func( 4, "how", "what", "why", "where" ); then int string_func( argn, argv ) int argn; char *argv; { int i; char **argp; argp = &argv; /* argp is a pointer to the first * string pointer */ for( i = 0; i < argn; i++ ) { printf( "%s\n", *argp++ ); } } Another (and probably better) way: string_func( "what", "why", "where", NULL ); or string_func( "what", "why", "where", "how", NULL ); then int string_func( argv ) char *argv; { char **argp; argp = &argv; /* now loop while the string pointer is not * set to NULL */ while( *argp != NULL ) { printf( "%s\n", *argp++ ); } } No, I didn't compile either example but they should give you a rough idea of how to do this. The examples assume that the stack grows in a negative direction. In both cases you set argp to the ADDRESS of the first string pointer on the stack. The CONTENTS of argp is the POINTER to the first string. Incrementing argp causes it to point to the second string pointer. Dave Burris ..att!ihuxz!burris
ariel@lznh.UUCP (<10000>Ariel Aloni) (10/22/88)
In article <3533@ihuxz.ATT.COM> burris@ihuxz.ATT.COM (Burris) writes: >> I want to write a function that accepts a variable number of string >> arguments. What is a possible way to do this? >> >> -pete >> > >In the C language arguments are placed on the stack in reverse order ^^^^^^^^^^^^^^^^ [ stuff deleted ] This is a convention adopted by most compilers, it was never promised by K&R (maybe somebody can enlighten us on ANSI-C ?). >No, I didn't compile either example but they should give you a rough >idea of how to do this. The examples assume that the stack grows in a ^^^^^^^^^^^^^^^^ >negative direction. ^^^^^^^^^^^^^^^^^^^ bad assumption -- e.g. 3B2/600 running SysVr3.1 is growing in a positive direction. Again, stack growth is never defined, it depends on the implementation. to the point : use either varargs (see man page) or you can always go to the simple "main" conventions (either "argv" convention or "arge" convention) in this case. >Dave Burris >..att!ihuxz!burris ariel -- Ariel A. Aloni att!ctsmain!raphel!ariel (201) 576-2937
rkl1@hound.UUCP (K.LAUX) (10/22/88)
In article <434@tutor.UUCP>, pete@tutor.UUCP (Peter Schmitt) writes: > I want to write a function that accepts a variable number of string > arguments. What is a possible way to do this? > The best place to look is the source code for the printf () function. Also, the header file 'varargs.h' has some helpful defines for writing just such functions. If you are using MSC 5.1, the reference manuals do describe and explain how to. --rkl
karl@haddock.ima.isc.com (Karl Heuer) (10/22/88)
In article <3533@ihuxz.ATT.COM> burris@ihuxz.ATT.COM (Burris) writes: >In the C language arguments are placed on the stack in reverse order This is not true in general. > string_func( "what", "why", "where", NULL ); In order for this to always work right, the NULL must be explicitly cast: (char *)NULL or (char *)0 are the two correct ways to write it. (Don't followup to say you don't believe this. Ask Chris Torek (mimsy!chris) to mail you the NULL article from his Frequently Asked Questions archive.) >The examples assume that the stack grows in a negative direction. If you write it with <stdarg.h>/<varargs.h>, you don't need to make that assumption. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
chris@mimsy.UUCP (Chris Torek) (10/22/88)
In article <3533@ihuxz.ATT.COM> burris@ihuxz.ATT.COM (Burris) writes: >In the C language arguments are placed on the stack in reverse order .... In the C language there may or may not *be* a stack. Pyramid's compiler places the first 12 (or so; it was 12 when we had one) `simple' arguments in registers. The machine can take the address of registers, so the first 12 arguments are in fact contiguous at increasing addresses. The 13th and succeeding arguments, however, are at some other location entirely (on the data stack---the registers are stored on the control stack, when the current window overflows). This is why you must use <varargs.h> (or <stdarg.h>). -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
pardo@june.cs.washington.edu (David Keppel) (10/22/88)
>>[ I want to do string varargs ] In article <3533@ihuxz.ATT.COM> burris@ihuxz.ATT.COM (Burris) writes: >[ In C, args are put on the stack in reverse order so the first arg > is the lowest arg of the stack ponter ] >[ example deleted ] NO! DON'T TOUCH THAT... <sound of muffled explosion> This is true on *some* machines, but is certainly false on other machines. There are a couple reasons why. One is that the C language doesn't define things to be done this way, so anybody who wants to push right-to-left can do so as long as their compiler works. I'm not sure that any modern compilers do this *currently*, but (a) there have been in the past and (b) there probably will be again. Another good reason why this isn't portable is that some machines have stacks that grow *up* and some have stacks that grow *down*. Finally, there is no guarantee that the arguments, even arguments of the same size, will be in contiguous memory. How to do this portably? Start with <varargs.h> or <stdargs.h>. Then go read <14015@mimsy.UUCP> (comp.lang.c, 16 Oct 1988). ;-D on ( "Every execution leaves you dangling..." ) Pardo -- pardo@cs.washington.edu {rutgers,cornell,ucsd,ubc-cs,tektronix}!uw-beaver!june!pardo
gwyn@smoke.BRL.MIL (Doug Gwyn ) (10/23/88)
In article <434@tutor.UUCP> pete@tutor.UUCP (Peter Schmitt) writes: >I want to write a function that accepts a variable number of string >arguments. What is a possible way to do this? There are two portable ways to do this as stated, using variable- argument facilities (you could also pass as a fixed argument a variable-sized data structure containing the strings). Either a count of the number of strings is passed as the first argument, or a null pointer (end marker) is passed after the last string. The two standard variable-argument facilities are associated with the headers <varargs.h> (most current implementations) and <stdarg.h> (ANSI C conforming implementations). I generally code for both, using #if __STDC__ as necessary to control compilation of the correct variation of the code. You should refer to your reference manual for details of these facilities, but here is an example extracted from the BRL/VLD MUVES project source code: #include <stdio.h> #include <string.h> #if __STDC__ #include <stdarg.h> #else #include <varargs.h> #endif #include <Er.h> /* error-logging package interface */ #include <Mm.h> /* memory-management package iface */ /* IoOpenFile() opens the file named by the concatenation of its variable character-string arguments for reading; it returns NULL if memory could not be allocated to build the pathname or if the file could not be opened (in which case ErIndex is set to `errnum'). The final argument must be (char *)NULL. */ #if __STDC__ FILE * IoOpenFile( long errnum, ... ) { #else /*VARARGS*/ FILE * IoOpenFile( va_alist ) va_dcl { long errnum; #endif va_list ap; register FILE *fp; /* opened file stream pointer */ register char *p; /* -> filename segment */ register char *cp; /* -> end of partial filename */ register int name_len; /* string allocation length */ char *fname; /* full path name of file */ /* allocate space for filename */ #if __STDC__ va_start( ap, errnum ); #else va_start( ap ); errnum = va_arg( ap, long ); #endif for ( name_len = 1; (p = va_arg( ap, char * )) != NULL; ) name_len += strlen( p ); va_end( ap ); if ( (fname = cp = MmVAllo( name_len, char )) == NULL ) return (FILE *)NULL; /* ErIndex already set */ /* construct concatenated filename */ #if __STDC__ va_start( ap, errnum ); #else va_start( ap ); (void)va_arg( ap, long ); /* skip errnum */ #endif while ( (p = va_arg( ap, char * )) != NULL ) while ( (*cp = *p++) != '\0' ) ++cp; va_end( ap ); /* try to open the file */ if ( (fp = fopen( fname, "r" )) == NULL ) ErSet( errnum ); /* deallocate filename space */ MmVFree( name_len, char, fname ); return fp; /* (may be NULL) */ }
gwyn@smoke.BRL.MIL (Doug Gwyn ) (10/23/88)
In article <3533@ihuxz.ATT.COM> burris@ihuxz.ATT.COM (Burris) writes: >In the C language arguments are placed on the stack in reverse order NO! NO! NO! Do not follow that fellow's advice if you are at all concerned about your code working on a wide variety of C implementations. What he said may apply to HIS particular machine but definitely is UNTRUE in general.
guy@auspex.UUCP (Guy Harris) (10/24/88)
>In the C language arguments are placed on the stack in reverse order >such that the first argument is the lowest index off of the stack pointer. *AHEM* No, in certain *implementations* of the C language arguments are placed onto the stack in reverse order.... In other implementations some of them are stuffed into registers. The closest things to a portable way of doing a function taking a variable number of arguments are: 1) "varargs" - present on many (most?) UNIX systems' C implementations, and possibly on other implementations as well (see VARARGS(n), for some value of "n", in the UNIX documentation; if you don't have UNIX, look somewhere else). 2) "stdargs" - specified by ANSI C, so probably present in many microcomputer implementations.
burris@ihuxz.ATT.COM (Burris) (10/24/88)
OK folks, enough already!!! In my attempt to be helpful in offering possible solutions to the requested problem I have received a few very patronizing responses. I tried to qualify my examples but obviously goofed by not being more specific. K & R pg. 186 copyright 1976 states, "...The order of evaluation or arguments is undefined by the language, take note that the various compilers differ." I was showing examples based on my experience with approx. 10 different C compilers on 4 different processors that all acted the way I stated. This is not necessarily the way your compiler will handle things. It is nonetheless an indication of how one might go about solving such a problem. I appreciate some of the responses that pointed out my omission of possibly important facts but some of you folks could stand to come down from your "high horse" long enough to take things in the nature they were intended, as attempts to be helpful to someone asking for solutions to problems they wish to solve. My apologies for not being more specific! Dave Burris ..!att!ihuxz!burris
henry@utzoo.uucp (Henry Spencer) (10/25/88)
In article <3533@ihuxz.ATT.COM> burris@ihuxz.ATT.COM (Burris) writes: >> I want to write a function that accepts a variable number of string >> arguments. What is a possible way to do this? > >In the C language arguments are placed on the stack in reverse order... No. In some C *implementations* they are placed on the stack in reverse order. In others they are placed on the stack in non-reverse order. In others they are passed in registers. In yet others, different types of arguments are passed in different kinds of registers. An implementation which uses registers will usually have to pass really big arguments on an in-memory stack anyway. And so on. Use <varargs.h> or <stdarg.h> (current practice and ANSI-C-draft practise respectively); they are the *only* portable way to do this. -- The dream *IS* alive... | Henry Spencer at U of Toronto Zoology but not at NASA. |uunet!attcan!utzoo!henry henry@zoo.toronto.edu
joshua@athertn.Atherton.COM (Sleaze Hack) (10/25/88)
In article <1962@lznh.UUCP> ariel@lznh.UUCP (<10000>Ariel Aloni) writes: > >[Lots deleted, but we're talking about the order arguments get pushed on > the stack during a C function call.] > >This is a convention adopted by most compilers, it was never promised >by K&R (maybe somebody can enlighten us on ANSI-C ?). > Not only does ANSI not promise us the order of arguments pushed on the stack, it does not promise us that this order will always be the same within a program! For example, the Tandem compiler (version C00 and later) pushes arguments left to right, unless the function takes a variable number of arguments, when it pushes them right to left. The standard says it is OK to force vararg functions to be prototyped before use, and Tandem requires this, so that it can always tell the difference between an "normal" function and a "vargargs" function. Obviously, having two different, and incompatible, stack frames in use in the same program can cause a lot of problems if you are not very careful. Think of all the problems that pointers to functions could cause! Tandem did this so that most function calls would be compatible with their other languages (PASCAL, TAL, etc.) which push arguments left to right. Tandem claims that this compiler is as ANSI conformant as possible (realizing that the standard is not a Standard yet). Summary on the portable use of variable arguments to a C function: use stdargs or varargs, or somewhere you will die. Josh -------- Quote: "If you haven't ported your program, it's not Addresses: a portable program. No exceptions." joshua@atherton.com OR sun!athertn!joshua OR {backbone}!{decwrl!hpda}!athertn!joshua work:(408)734-9822 home:(415)968-3718
gwyn@smoke.BRL.MIL (Doug Gwyn ) (10/25/88)
In article <3542@ihuxz.ATT.COM> burris@ihuxz.ATT.COM (Burris) writes: >I appreciate some of the responses that pointed out my omission of >possibly important facts but some of you folks could stand to come down >from your "high horse" long enough to take things in the nature they >were intended, as attempts to be helpful to someone asking for solutions >to problems they wish to solve. Probably the main reason you were flamed for your attempt to be helpful is that the advice you gave was poor. There is a well-defined mechanism for dealing with variable function arguments, and users of the mechanism do not have to worry about their code breaking in mysterious ways when it is ported to a different architecture, as it would have had your advice been followed. Whenever a fairly convenient portable solution to a problem exists, it should be used in preference to one that relies on nonportable details of a particular implementation. It is particularly galling to see such a suggestion coming out of AT&T, considering all the hours I have spent in tracking down and fixing this exact problem in source code that AT&T licensed commercially. I hope you AT&T hackers learn how to use the official variable argument mechanism and save us all a lot of unnecessary grief.
pardo@june.cs.washington.edu (David Keppel) (10/26/88)
henry@utzoo.uucp (Henry Spencer) writes: >[ arguments passed: forwards, backwards, registers, ... ] This probably seems like a silly question, but are there any compilers that pass arguments globally? Things of the form static void foo (m, n) int m, n; { if (m==0) return; m = bletch (m,n); foo (m,n); } Would win from this. I doubt that these account for a significant part of the usage. -- pardo@cs.washington.edu {rutgers,cornell,ucsd,ubc-cs,tektronix}!uw-beaver!june!pardo
gwyn@smoke.BRL.MIL (Doug Gwyn ) (10/26/88)
In article <6199@june.cs.washington.edu> pardo@uw-june.UUCP (David Keppel) writes: >This probably seems like a silly question, but are there any compilers >that pass arguments globally? In general, C semantics require that a function invocation's value parameters be unique to the activation record. They cannot be shared. Your particular example would allow that optimization, IF all users of the function were known to the compiler at the point that it was deciding what form of function linkage to use for that function. However, it is doubtful that the extra analysis and irregular linkage mechanism would be worthwhile for such an unlikely case.
alfie@warwick.UUCP (Nick Holloway) (10/26/88)
In article <3533@ihuxz.ATT.COM> burris@ihuxz.ATT.COM (Burris) writes: >In the C language arguments are placed on the stack in reverse order > Demonstration 1: main () { int i = 1; printf ( "%d %d %d\n", i++, i++, i++ ); } Note: I _do_ know that this is bad code - but it does demonstrate the order of evaluation. First I compiled and ran this on a sun3. The output is what most people expect from their compiler. (args evaluated from right to left) 3 2 1 Then I compiled it on the sun4 here (sparc), and the results suprised me! 2 1 3 Looking at the assembly, it was confusing, but it did seem rather long, so I compiled with -O, and this gave 1 2 3 I think this is a good demonstration of why you must never depend on the order evaluation of arguments (On the sparc, even compile time flags make a difference). Demonstration 2: test (a,b) int a,b; { printf ( "&a=%u\n&b=%u\n", (unsigned)&a, (unsigned)&b ); } main () { test ( 1, 2 );} On the sun3, the output was: (args at increasing addresses) &a=251657624 &b=251657628 On the sun4: (args at decreasing addresses) &a=4160748428 &b=4160748432 So we have concrete examples why you can never assume anything about the calling convention if you wish your programs to be portable, and use a standard interface such as <varargs.h>/<stdargs.h>. Note: I normally indent my programs, this is just to cut down on space in this article. Also I did include <stdio.h>. -- JANET : alfie@uk.ac.warwick.cs | `O O' |16 Queens Rd| /: : :-- : :-- UUCP : ..!mcvax!ukc!warwick!alfie |// ^ \\|Hertford | / : : : : : BITNET: alfie%uk.ac.warwick.cs@ukacrl --------|Herts | /--: : :- : :- ARPA : alfie%cs.warwick.ac.uk@cunyvm.cuny.edu|England |/ : :__ : : :__
ron@motmpl.UUCP (Ron Widell) (10/30/88)
In article <787@ubu.warwick.UUCP> alfie@warwick.UUCP (Nick Holloway) writes:
[An otherwise good example of argument evaluation ordering]
=Demonstration 2:
= test (a,b) int a,b;
= { printf ( "&a=%u\n&b=%u\n", (unsigned)&a, (unsigned)&b ); }
= main () { test ( 1, 2 );}
=
=On the sun3, the output was: (args at increasing addresses)
= &a=251657624
= &b=251657628
=On the sun4: (args at decreasing addresses)
^^^^^^^^^^ Huh ?
= &a=4160748428
= &b=4160748432
I'm not sure what you mean here. It appears to me that the address of
b is higher than that of a, just like the sun3 (it's certainly a larger
number ;-)).
=JANET : alfie@uk.ac.warwick.cs | `O O' |16 Queens Rd| /: : :-- : :--
=UUCP : ..!mcvax!ukc!warwick!alfie |// ^ \\|Hertford | / : : : : :
=BITNET: alfie%uk.ac.warwick.cs@ukacrl --------|Herts | /--: : :- : :-
=ARPA : alfie%cs.warwick.ac.uk@cunyvm.cuny.edu|England |/ : :__ : : :__
--
Ron Widell, Field Applications Eng. |UUCP: motmpl!ron
Motorola Semiconductor Products, Inc., |Voice:(612)941-6800
9600 W. 76th St., Suite G | If they *knew* what I was saying,
Eden Prairie, Mn. 55344 -3718 | do you think they'd let me say it?
crossgl@ingr.UUCP (Gordon Cross) (11/01/88)
In article <3533@ihuxz.ATT.COM>, burris@ihuxz.ATT.COM (Burris) writes: > In the C language arguments are placed on the stack in reverse order > such that the first argument is the lowest index off of the stack pointer. > This allows you to pass the first argument as a count of the number of > following arguments. > > Example: [ example deleted to save space ] > > In both cases you set argp to the ADDRESS of the first string pointer > on the stack. The CONTENTS of argp is the POINTER to the first string. > Incrementing argp causes it to point to the second string pointer. > The proper way to access variable numbers of arguments passed to a routine is to use use <varargs.h>!! Any assumptions about stack layout is just asking for trouble (for example some compilers pass the first couple of args in registers for efficiency reasons). Check your manuals or any good "C" programming book on how to use these macros.... Gordon Cross Intergraph Corp. Huntsville, AL