crm@duke.UUCP (10/14/83)
Can any of you C wizards out there tell me how it is one implements variable arguments in C? Also, many thanks to all the people who responded to my request for a better cb -- I even got one in the mail today! It's all in, and it works, and I would send out individual thanks to all the people who responded except there were lots(!) of them. Anyway, thanks again ... how you say ... :-) Charlie Martin ...!duke!crm
henry@utzoo.UUCP (Henry Spencer) (10/16/83)
How do you implement variable numbers of arguments in C? In a word, unportably. (Is that a word?) The implementation is fundamentally machine-dependent. There are portable "library" facilities for doing it in some Unixes, but the insides of those libraries are still quite machine-dependent. Scanning a variable-length argument list requires knowing the C calling sequence on the machine in question, so that you know how the arguments are laid out in core. Machines differ enough on this point that machine-independent code for it is impossible. -- Henry Spencer @ U of Toronto Zoology {allegra,ihnp4,linus,decvax}!utzoo!henry
dave@utcsrgv.UUCP (Dave Sherman) (10/16/83)
Charlie Martin (duke!crm) asks how to implement variable arguments.
In C or on a particular machine? As Henry Spencer points out, it's not
portable and therefore not strictly valid C. However, on a PDP-11
or VAX, you can have the routine
routine(firstarg)
int *firstarg;
{
int **argptr;
argptr = &firstarg;
...
argptr++;
...
}
and refer to *argptr to mean your arguments, **argptr if you want
the character it points to, etc. I have several programs which do
this sort of thing. It's obviously not guaranteed to be portable
to other machines.
It is a useful construct, though, and it seems quite likely that
for any given machine you want to take such code to, you can figure
out what needs doing. Those arguments have to get passed somehow,
so although the incrementing might be different the same basic
technique should continue to work.
Dave Sherman
Toronto
--
{cornell,decvax,ihnp4,linus,utzoo,uw-beaver}!utcsrgv!lsuc!dave
kendall@wjh12.UUCP (Sam Kendall) (10/17/83)
Henry@Utzoo notes, and seems to object to, the fact that variable argument functions are implemented nonportably, even though the package has a portable interface. It seems to me that one of the good points of portable libraries such as the Standard I/O Library and the portable C library in general (not that there is just one) is the possibility of having a portable interface but a nonportable implementation. There are other functions be that cannot have a single, portable implementation: setjmp() and longjmp(), for instance; and it may be advantageous to code functions in assembler or nonportable C, for efficiency, that could be coded portably in C. Here is a real difference between Ada and C (how perceptive of me!): Ada is designed to make it much easier to give even seemingly machine-dependent functions portable implementations, and to make it easy to seperate the machine-dependent from the machine-independent otherwise. This is done by (1) moving machine dependencies into the compiler, and (2) providing good language facilities for seperation, such as (in C terms) the ability to seperate the structure members from their layout, and to seperate enum members from their numeric values. Not to mention a good way to seperate the government from its money. Sam Kendall {allegra,ihnp4}!wjh12!kendall Delft Consulting Corp. decvax!genrad!wjh12!kendall
henry@utzoo.UUCP (Henry Spencer) (10/22/83)
I'm not so much *objecting* to the machine-dependent nature of variable-length-arg-list routines, as trying to point out that their implementation *is* fundamentally machine-dependent and there is *no* *way* *around* *this*. This is in response to numerous people proposing one notion after another of how to do something that simply cannot be done. Worse, some of their schemes do work on *some* machines, and people who don't understand the messiness of the issue might assume that they work everywhere. I've had enough encounters with unportable software as a result of such assumptions to think it worthwhile to try to head this particular problem off. Yes, I'm aware of the library packages under 4BSD and System V that try to at least bury the machine-dependencies in a library. Be warned that even they don't suffice on sufficiently bizarre machines. The most common reason for wanting vararg routines other than the standard ones is a desire to write an error-handling routine that puts out a printf-style message and then does some program-dependent cleanup actions. The *only* 100% portable way to do this is: sprintf(buf, ".....", ....); error(buf); I know it's a nuisance to do two calls instead of one, and the need to have a buffer variable is annoying, but this code is guaranteed to be fairly portable, while using %r, _doprnt, &args, etc. is not. -- Henry Spencer @ U of Toronto Zoology {allegra,ihnp4,linus,decvax}!utzoo!henry
ken@turtleva.UUCP (Ken Turkowski) (10/24/83)
Another way to get portable error message routines is to assume that
there will be a maximum number of arguments.
error(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
char *fmt;
int arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10;
{
fprintf(stderr, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
arg8, arg9, arg10)
}
The only time that this wouldn't work is if the arguments were put on
the stack in the reverse order that they normally are in C.
Ken Turkowski
CADLINC, Palo Alto
{decwrl,amd70}!turtlevax!ken
warren@ihnss.UUCP (10/26/83)
The technique of declaring a function with the maximum number of expected arguments and then passing them on: foo(a1,a2,a3,a4,...an) char *a1,*a2, ..., *an; { error(errno,fmt,a1, ..., an); DOES NOT work in all implementations. An obvious failure occurs when the stack isn't big enough to accomodate all of the arguments that aren't passed to foo. A less obvious problem that I have seen (I forget exactly which machine it was on) is that the compiler passes the pointer arguments using "effective address" type instructions to get the pointer, rather than just copying the bits, and the machine generates some sort of fault if the address in the pointer is invalid. Since the junk you pick up on the stack can to be an invalid address, your code randomly fails depending on what happens to be on the stack. -- Warren Montgomery ihnss!warren IH x2494
andree@uokvax.UUCP (10/28/83)
#R:duke:-363700:uokvax:3000004:000:438 uokvax!andree Oct 26 08:45:00 1983 /***** uokvax:net.lang.c / turtleva!ken / 12:48 pm Oct 24, 1983 */ The only time that this wouldn't work is if the arguments were put on the stack in the reverse order that they normally are in C. Ken Turkowski CADLINC, Palo Alto {decwrl,amd70}!turtlevax!ken /* ---------- */ Unfortunatly, there is at least one compiler out there that does this. Printf for this compiler is interesting (and broken) (and sickening). <mike
thomas@utah-gr.UUCP (Spencer W. Thomas) (10/31/83)
Re: S-1 upward growing stack. (Of course, this depends on your hardware cooperating.) The way I would solve the problem would be to have the frame pointer point to the first argument (or, perhaps, to the word above the first argument), so that args would be at (constant) negative offsets form the frame pointer, and local vars would be at positive offsets. Then you don't have a problem with getting the wrong arg when called with the wrong number of them. =Spencer
ggr@pyuxbb.UUCP (11/04/83)
> Re: S-1 upward growing stack. > > (Of course, this depends on your hardware cooperating.) The way I would > solve the problem would be to have the frame pointer point to the first > argument (or, perhaps, to the word above the first argument), so that args > would be at (constant) negative offsets form the frame pointer, and local > vars would be at positive offsets. Then you don't have a problem with > getting the wrong arg when called with the wrong number of them. > > =Spencer Yes, I can testify that this scheme works fine. I used negative offsets for arguments in the Data General Nova/Eclipse C compiler I wrote, since their hardware stacks also grew upward. With appropriate modification of /usr/include/varargs.h, functions that expect a variable number of arguments (and use varargs, of course) will even work with this "unconventional" stack structure. === Guy Riddle == AT&T Bell Laboratories, Piscataway ===
ajs@hpfcla.UUCP (11/06/83)
#R:duke:-363700:hpfcla:1500001:000:1014 hpfcla!ajs Nov 4 15:01:00 1983 The HP9000 Series 500 also has a stack which grows upwards in address space. We attacked the variable-number-of-arguments problem this way: 1: Push the return area first (two words). 2: Push the arguments in reverse order (right to left), so the left-most is highest on the stack, at a known offset from the frame pointer. 3: Push additional information, including a return area pointer and a number-of-arguments word. A C program can't get to the additional information cleanly but it can be done if necessary. Either the return area pointer or number of arguments may be useful. Also, be warned that execl(2), execlp(2), and execlv(2) make assumptions about the order of the arguments (at least for System III). If you reverse that order, you have to correct the intrinsics. (I hope this is of general enough interest to merit posting it instead of responding by mail...) Alan Silverstein, hpfcla!ajs Hewlett-Packard Fort Collins Systems Division, Colorado
jdb@mordor.UUCP (John Bruner) (11/10/83)
Now that all of the mail has come in, here is a summary of the responses I received to my inquiry about argument passing in C. The consensus was that it is "legal" to implement a compiler for which functions that do not use "varargs" must be called with the same number of arguments with which they were defined. This would mean that if the 4.2BSD "open" were declared as open(path, flags, mode) char *path; int flags, mode; { then calling it in the old way open("/dev/null", 0); would be incorrect. Although such an implementation is "legal" it is undesirable because many programs from more permissive environments (e.g. the VAX) depend upon this characteristic. (One example of this occurs in the Portable C compiler itself.) Several people also pointed out that right-to-left evaluation of the arguments would place the first argument at a constant offset from the called routine's stack frame, regardless of the direction of stack growth. I should have mentioned in my original inquiry that we chose left-to-right evaluation because we wanted the arguments to be stored with ascending addresses. Some C programs desire this characteristic as well. The other method for handling cases such as the one above is to use a register as an argument pointer. The AP points to the first argument and all variables are referenced with positive offsets from the AP. We are changing the calling sequence for the S-1 compiler from one calling mechanism (JSR/RETSR) to another one (CALL/UNCALL) that was originally intended for another language implementation. This will allow us to pass an argument pointer in an efficient way. All of the usual "tricks" with regard to argument passing in C should then work "correctly". Thanks for all of the help. John Bruner S-1 Project/Lawrence Livermore National Laboratory
greg@vecpyr.UUCP (Greg Millar) (04/11/86)
I have always heard that varargs is not very portable. Is this really true? If you know of any machine that is running 4.X BSD, System III/V, Xenix or any other real unix that doesn't support varargs, please let me know. Under AIX there are 3 functions associated with varargs called: vsprintf, vprintf, vfprintf. Are these only available on the IBM RT PC? Greg Millar ...{ucbvax,decwrl}!dual!vecpyr!greg Visual Engineering, Inc. 2680 N. First San Jose, CA 95134 (408) 945-9055
grr@cbmvax.cbm.UUCP (George Robbins) (04/12/86)
In article <272@vecpyr.UUCP> greg@vecpyr.UUCP (Greg Millar) writes: >I have always heard that varargs is not very portable. Is this really >true? If you know of any machine that is running 4.X BSD, System III/V, >Xenix or any other real unix that doesn't support varargs, please let >me know. > >Under AIX there are 3 functions associated with varargs called: >vsprintf, vprintf, vfprintf. Are these only available on the IBM RT PC? > > Greg Millar {ucbvax,decwrl}!dual!vecpyr!greg > Visual Engineering, Inc. 2680 N. First San Jose, CA 95134 You have to define precisly what you mean by varargs... The strict/slimey definition that works on many/most unix systems is that a *C* function can index through its argument list in a linear fashion by taking the address of the first argument and incrementing by the length of each argument (which you must know or be told). This assumes that the arguments are all stored in some contiguous, rational order on the stack or in some parameter block. It is also generally assumed that a function can pass its arguments to a function it calls, without knowing anything about them. (frequent example: debug functions whose arguments are passed to printf) Since these conventions are known not to work on all machines, it was decided to create a set of 'magical' varargs routines that would allow a C program to access it's arguments in a machine independent way. Supposedly the vprintf, etc. routines are reimplementations of printf, etc. that make use of the these machine independent varargs conventions. As you might expect, implementations where strict/slimey varargs works on the hardware people tend to be careless about implementing/using the machine independent form, and people who are stuck with implementations that require the machine independent form tend to be kind of bitter about 'portable' code created using the strict/slimey conventions. -- George Robbins - now working with, uucp: {ihnp4|seismo|caip}!cbmvax!grr but no way officially representing arpa: cbmvax!grr@seismo.css.GOV Commodore, Engineering Department fone: 215-431-9255 (only by moonlite)
ark@alice.UucP (Andrew Koenig) (04/13/86)
> I have always heard that varargs is not very portable. Is this really > true? If you know of any machine that is running 4.X BSD, System III/V, > Xenix or any other real unix that doesn't support varargs, please let > me know. > Under AIX there are 3 functions associated with varargs called: > vsprintf, vprintf, vfprintf. Are these only available on the IBM RT PC? I am the author of varargs. If you find any machine with a sensible architecture that cannot be made to support varargs, I would greatly like to hear about it. I also wrote the v*printf functions. As far as I know, they are a standard part of System V.
kalash@ingres.berkeley.edu.ARPA (Joe Kalash) (04/18/86)
>Under AIX there are 3 functions associated with varargs called: >vsprintf, vprintf, vfprintf. Are these only available on the IBM RT PC? > These functions are available under any system that conforms to the SVID. Joe Kalash kalash@berkeley ucbvax!kalash
blarson@usc-oberon.UUCP (04/21/86)
I just wrote the varargs.h header file for os9/68000 from the 4.2 BSD documentation, (rather than hacking up the non-portable code in microemacs) and would like a few clarifacations: Must va_alist be the only thing in the argument list? (If this is not true, I don't see how to implement varargs with this compiler.) (The example in the documentation seems to back up my assumption.) Is it leagal to pass a the rest of an argument list to another function expecting it? If so, should it be passed as a pointer to a variable of type va_list? (Without this capability, I supose I'll have to document this as a non-portable use of varargs.) I assume va_start be done in the original function. (Dito the first va_alist comment.) Does va_end have to be done in the original function also? (va_end does nothing in my implementation.) Thanks. I do plan on making this available to other os9/68000 users, preferably by talking microware into distributing it with the next release of thier C compiler. -- Bob Larson Arpa: Blarson@Usc-Ecl.Arpa Uucp: ihnp4!sdcrdcf!usc-oberon!blarson
ark@alice.UucP (Andrew Koenig) (04/22/86)
> Must va_alist be the only thing in the argument list? (If this is not > true, I don't see how to implement varargs with this compiler.) (The > example in the documentation seems to back up my assumption.) Yes, va_alist must be the only thing in the argument list. However, you can use #define to make va_alist expand into something bigger. That possibility, in fact, is the reason that va_alist must be the only thing in the argument list. > Is it leagal to pass a the rest of an argument list to another > function expecting it? If so, should it be passed as a pointer to a > variable of type va_list? (Without this capability, I supose I'll > have to document this as a non-portable use of varargs.) Yes, it is legal. You may pass either a pointer to a va_list or the entire va_list itself. Passing the pointer is recommended, because on some implementations the va_list may be quite large and therefore slow to copy. If you do pass the pointer, using va_arg in the subroutine will advance the argument list pointer as seen by the caller. > I assume va_start be done in the original function. (Dito the first > va_alist comment.) Does va_end have to be done in the original > function also? (va_end does nothing in my implementation.) It should be. (va_end does nothing in every implementation I've seen)
rb@ccird2 (04/25/86)
In article <5302@alice.uUCp> ark@alice.UucP (Andrew Koenig) writes: >> I have always heard that varargs is not very portable. Is this really >> true? If you know of any machine that is running 4.X BSD, System III/V, >> Xenix or any other real unix that doesn't support varargs, please let >> me know. > >If you find any machine with a sensible architecture that cannot >be made to support varargs, I would greatly like to hear about it. > The concern about about varargs is brought up in "Software Tools" by Kernigan and Plauger. The main concern is that certain systems and languages have the caller push the arguments, and have the callee destroy them when they are finished. This is common practice in Fortran and Pascal. The big concern with C is that there might be a compiler out there which has C/Pascal|Fortran compatibility. Since these compilers seem to be the exception rather than the rule, and newer versions of these languages are tending to follow C conventions, this is not likely to be a problem for *most* environments. I have heard that there are a few "peculiar" compilers available for the Atari ST, Mac, and Amiga, which, although not "kosher", CAN support most varargs situations. The problems that can occur are "intelligent" compilers which put arguments directly into registers rather than on the stack. Appearantly, this can be a real problem if you wish to "intercept" a system call at the application side. Why do so many of the micro operating systems insist on putting arguments in registers!!!. Even MS-DOS expects arguments in registers rather than on the stack. The C frame is a more sensible archetecture, but not the only one. Since you specifically asked about UNIX based systems, you can be relatively unconcerned. There are non-portable ways to USE varargs. The classic is to put a long indicator into the "format argument" and pass an int. Do this with a couple of arguments where ints are 16 bits, and longs are 32 bits, and you will return to "never never land". The normal usages (printf, scanf,...) aren't usually a problem, but there are a few "mix and match" functions using varargs which selectively mix and match various modifiable stack addresses, and will "core dump" the whole system. try this: (comments are for 16 bit ints, 32 bit longs, 32 bit pointers). main() { /* top of frame = return address */ int i; long l; scanf("%d %d",&i); /* second argument missing, clobbers frame */ scanf("%d",i); /* cute "poke" of i, can demolish code or core dump */ scanf("%ld",&i); /* extra 16 bits is usually frame pointer or return address */ scanf("%d",l); /* 16 bits of "garbage" plus your number possibly munged beyond recognition due to byte ordering */ } Lint will pass it, assuming printf is declared /*VARARGS*/, and the compiler won't even sneeze. But running it will give you "buss error core dumped" or something equally nasty. This is one of the few areas where lint will not protect you. Anyone figured out a syntax checker for these functions? Of course, you should use a syntax checker for any of these functions. Another cute trick I've seen is using varargs to pass integers to functions which assign to pointers. Such as: main() { int read(); init(0x20L,&read); /* set exception vector */ } /*VARARGS*/ init(a,b) char **a,*b,**i; { *a=b; /* poke absolute value with a valid address */ } This is the ultimate in unportability, but is frequently "hidden" in "hostile" PC programs, typically to mount new device drivers and remove them when the code is complete. Just try plugging one of these into unix unmodified :-).
grr@cbmvax (04/27/86)
In article <792@ccird2.UUCP> rb@ccird2.UUCP (Rex Ballard) writes: >In article <5302@alice.uUCp> ark@alice.UucP (Andrew Koenig) writes: >>> I have always heard that varargs is not very portable... ... >I have heard that there are a few "peculiar" >compilers available for the Atari ST, Mac, and Amiga, which, although >not "kosher", CAN support most varargs situations. The problems that >can occur are "intelligent" compilers which put arguments directly >into registers rather than on the stack. Appearantly, this can be >a real problem if you wish to "intercept" a system call at the >application side. Why do so many of the micro operating systems >insist on putting arguments in registers!!!. Even MS-DOS expects >arguments in registers rather than on the stack. Mainly cause it makes calling subroutines very fast! (and breaks a lot of code) imagine: routine(arg); register char *arg; {...} If the compiler knows that arg just happens to be in a suitable register when the routine is called; the only overhead is an optional register to register move, and a call instruction. This can really speed things up when you have a lot of little inner routines. However, spare us compiler writers! It just isn't worth it when you're trying to use somebody else's 'portable' code. It would be fine if C had nested procedures or inlines or something, but a disaster otherwise. > >The C frame is a more sensible archetecture... > Most micro operating systems, includeing MSDOS include some degree of conceptual compatibility with CP/M, and the CP/M system system calls were intended to be used from assembly language programs, thus getting the arguments in registers was easier than not. Kind of like the influence the PDP-9 assembler had on the selection of * and & for the C address operators, when @ and # make a lot more sense to anybody brought up on a PDP-11. -- George Robbins - now working with, uucp: {ihnp4|seismo|caip}!cbmvax!grr but no way officially representing arpa: cbmvax!grr@seismo.css.GOV Commodore, Engineering Department fone: 215-431-9255 (only by moonlite)
mccaugh@uiucdcs.CS.UIUC.EDU (04/29/86)
It is a truism that MS-DOS prefers that arguments be passed register-wise; in part this is due to the anticipation that the routine in question to receive the arguments is an interrupt-routine with interrupts (hopefully) disabled, so it must proceed about its business most hastily, less a (possibly) more desrving interrupt get neglected. Some architectures -- most notably, the IBM-360/370 -- allowed for "load multiple" and "store multiple" commands which saved the whole bank of regis- ters in one instruction. --Scott McCaughrin
eric@chronon (05/02/86)
In article <129@drilex.UUCP> dricej@drilex.UUCP writes: > >rb@ccird2 (Rex Ballard) wonders what kind of systems would not be able to >handle varargs. ... >... Therefore, a more proper question would be: is there any >architecture which is suitable for a C compiler, but not for varargs? Yes! I can think of an example close to home... An architecture with a large (LARGE) number of registers, a sliding window to allow reference to a smaller register set locally within a procedure, and OS support for using the register set as a stack (handling overflow/underflow). The first <n> arguments are passed in registers via the overlapped sliding window, remaining have to be passed in memory. The problem is that no choice of <n> will be correct; you can only make arbitrarily small the probability of it not being big enough... and at the cost of additional expense elsewhere... I assert that this architecture, and the rest of what goes with this particular feature, is particularly well-suited for efficient execution of programs written in C. >P.S. Microcomputers pass things in registers, rather than on the stack, >because stack operations are slow relative to register operations. This >is also typical of assembly language programming, rather than C language >programming. >Not everybody is willing to pay the high-level language penalty. > >Craig Jackson >UUCP: {harvard,linus}!axiom!drilex!dricej Microcomputers aren't the only ones interested in the fact that using registers is faster than using memory. Does this argument sound RISC-y? Note that nothing in the C language requires this particular high-level language penalty (passing args in memory rather than in registers). The varargs kludge is for convenience only (yes, I like it, too, and would chafe at Pascal-like restrictiveness!). -- Eric Black "Garbage In, Gospel Out" UUCP: {sun,pyramid,hplabs,amdcad}!chronon!eric WELL: eblack BIX: eblack
eric@chronon (05/02/86)
Sorry, but I left out an important point from my previous posting about vararg difficulties. My article should in no way be construed as arguing against allowing a variable number of arguments being passed to a called function. Rather, it points out that code that *ASSUMES* that varargs are passed in memory in ascending addresses *IS A HIGHLY MACHINE-DEPENDENT ASSUMPTION* and is *NOT PORTABLE CODE*. Library support to handle variable argument lists in a standardized way is appropriate (see varargs.h on BSD systems for something which comes very close). These library routines are quite simple on a traditional architecture (which is assumed by too many existing pieces of code -- printf is too many already!). -- Eric Black "Garbage In, Gospel Out" UUCP: {sun,pyramid,hplabs,amdcad}!chronon!eric WELL: eblack BIX: eblack
ark@alice.UucP (Andrew Koenig) (05/02/86)
> Some architectures -- most notably, the IBM-360/370 -- allowed for "load > multiple" and "store multiple" commands which saved the whole bank of regis- > ters in one instruction. Of course, that one instruction almost always takes more time (but less space) than an equivalent sequence of ordinary loads or stores.
ark@alice.UucP (Andrew Koenig) (05/03/86)
I think people are confusing two different meanings for the same term: 1. the practice of writing programs that accept varying numbers of actual parameters by declaring a single formal parameter, taking its address, and incrementing that address in various devious ways. 2. the practice of writing programs that accept varying numbers of actual parameters and access them using ONLY the facilities provided by <varargs.h> . The particular implementation of these facilities may differ from one machine to another. I said I don't know offhand of a machine that can't implement #2. I am being deluged by descriptions of machines that can't implement #1.
greg@utcsri.UUCP (Gregory Smith) (05/03/86)
In article <236@chronon.chronon.UUCP> eric@chronon.UUCP (Eric Black) writes: >In article <129@drilex.UUCP> dricej@drilex.UUCP writes: >> >>rb@ccird2 (Rex Ballard) wonders what kind of systems would not be able to >>handle varargs. ... >>... Therefore, a more proper question would be: is there any >>architecture which is suitable for a C compiler, but not for varargs? > >Yes! I can think of an example close to home... An architecture with >a large (LARGE) number of registers, a sliding window to allow reference >to a smaller register set locally within a procedure, and OS support >for using the register set as a stack (handling overflow/underflow). >The first <n> arguments are passed in registers via the overlapped >sliding window, remaining have to be passed in memory. The problem >is that no choice of <n> will be correct; you can only make arbitrarily >small the probability of it not being big enough... and at the cost of >additional expense elsewhere... >I assert that this architecture, and the rest of what goes with this >particular feature, is particularly well-suited for efficient execution >of programs written in C. > I agree with your assertion. If this machine supports pointers to registers, you could write a varargs. va_arg() would have to bump a pointer to the last register arg to a pointer to memory, maybe by calling a 'va_bump' function. If it doesn't support pointers to register args, then it is in a bit of trouble with C because this is supposed to be legal: f(a) int a; { wombat(&a); } -- "For every action there is an equal and opposite malfunction" ---------------------------------------------------------------------- Greg Smith University of Toronto UUCP: ..utzoo!utcsri!greg
eric@chronon.UUCP (Eric Black) (05/08/86)
Yes, this is slightly to the side of the original question as to whether it is POSSIBLE to write a varargs() handler (a la 4.2 manpage) for any given machine architecture, but the discussion is legitimately moving around that target... In article <2694@utcsri.UUCP> greg@utcsri.UUCP (Gregory Smith) writes: >In article <236@chronon.chronon.UUCP> eric@chronon.UUCP (Eric Black) writes: >>In article <129@drilex.UUCP> dricej@drilex.UUCP writes: >>>rb@ccird2 (Rex Ballard) wonders what kind of systems would not be able to >>>handle varargs. ... >>>... Therefore, a more proper question would be: is there any >>>architecture which is suitable for a C compiler, but not for varargs? [I guess I answered a slightly different question here:] >>Yes! I can think of an example close to home... An architecture with >>a large (LARGE) number of registers, a sliding window to allow reference >> [... description of register stack machine ...] >>I assert that this architecture, and the rest of what goes with this >>particular feature, is particularly well-suited for efficient execution >>of programs written in C. >> >I agree with your assertion. If this machine supports pointers to registers, >you could write a varargs. va_arg() would have to bump a pointer to the last >register arg to a pointer to memory, maybe by calling a 'va_bump' function. >If it doesn't support pointers to register args, then it is in a bit of >trouble with C because this is supposed to be legal: > > f(a) int a; > { wombat(&a); > } >-- Yup. This is legal, and is permitted. This machine DOES allow you to take the address of a register, but it's an expensive feature to support, and we'd like to get rid of it. Other systems take care of this at the compiler level, and it crops up with register variables, not just arguments -- if you take the address of a variable, it can't reside in a register, but must be copied into memory. Possible aliasing with pointer arithmetic gets quite hairy, but that's a dangerous [and generally non-portable] thing to do in an undisciplined manner. This brings me back to my point (sort of). This is the same problem that other machines have with register variables and getting at them in two different ways (by name and at the other end of a pointer). In the case of varargs, the "by name" is as a formal parameter, the pointer is the usual varargs method. Accessing varargs directly is just as sloppy as doing something like this: foo() { int a, b, *intp; intp = &a; *intp = 1; /* set a to 1 */ intp++; *intp = 2; /* of course, this sets b to 2, doesn't it? */ } If you think this is good coding practice, I don't want you working for me! If you object to this technique, why is direct accessing of varargs items OK? Again, I realize this is not answering the precise question in the original posting, but it's worth discussing. Thanks for putting up with me... -- Eric Black "Garbage In, Gospel Out" UUCP: {sun,pyramid,hplabs,amdcad}!chronon!eric
@hpislx.UUCP (05/08/86)
This message is empty.
ark@alice.UucP (Andrew Koenig) (05/10/86)
> Hypothetical but quite beleivable: On a 68000, pass the first N > 32-bit integer (int, long, etc.) arguements in data regisers and the > first M (32-bit) pointer arguments in address registers. There isn't > a typeof operator, and the hack of determining the data type by doing > string manipulations on the quoted type, besides preprocessor > replacements in quoted strings being a pcc oddity, breaks when faced > with typedefs. (I think argument quoting via a different meathod is > proposed in the current ansi C draft.) > > This is true of any architecture with different register types with > identical size. (Otherwise the type could be determined by sizeof, > which I do in the varargs.h implementation I wrote.) Any proposted > solutions, other than not having such a compiler on such a machine? If a pointer argument is passed in a different place from an integer argument of the same size, then implementing varargs requires some help from the compiler. But such an implementation is going to have trouble in any event because even today there are sometimes programs that forget to, say, declare the type of an argument. This is especially true when that argument is merely passed to some other function.