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
rb@ccird2.UUCP (Rex Ballard) (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 :-).
eric@chronon.UUCP (Eric Black) (05/01/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.UUCP (Eric Black) (05/01/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/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
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.