From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,bc41e6a6a2da78a9 X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 2002-08-16 12:41:38 PST Path: archiver1.google.com!news1.google.com!newsfeed.stanford.edu!news-spur1.maxwell.syr.edu!news.maxwell.syr.edu!wn1feed!worldnet.att.net!bgtnsc05-news.ops.worldnet.att.net.POSTED!not-for-mail From: "David Thompson" Newsgroups: comp.lang.ada References: <87sn1s6f6a.fsf@almroth.com> <87ptww7yj6.fsf@almroth.com> <87vg6nj8jd.fsf@almroth.com> Subject: Re: Variable arguments magic in Ada to C code X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 5.00.2615.200 X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2615.200 Message-ID: Date: Fri, 16 Aug 2002 19:41:37 GMT NNTP-Posting-Host: 12.89.145.190 X-Complaints-To: abuse@worldnet.att.net X-Trace: bgtnsc05-news.ops.worldnet.att.net 1029526897 12.89.145.190 (Fri, 16 Aug 2002 19:41:37 GMT) NNTP-Posting-Date: Fri, 16 Aug 2002 19:41:37 GMT Organization: AT&T Worldnet Xref: archiver1.google.com comp.lang.ada:28136 Date: 2002-08-16T19:41:37+00:00 List-Id: Andreas Almroth wrote : > lutz@iks-jena.de (Lutz Donnerhacke) writes: [ calling C variable-argument functions ] > Well, I'm merely interfacing to an existing C library. I do heaps of type- > and value checking before passing on to the C function, and thus trying to > limit the consequences of incorrect arguments. ... > > >When using VA in C, you build a list of pointers (System.Address) to your > > >arguments, and terminate the list with NULL (Null_Ptr). > > Not true, at least not in general. The actual argument-passing mechanism(s), for both vararg and non-vararg functions, are not defined by the C standard only by implementation(s) (so in principle you need to say not "in C" but "in MSVC++6" or "in gcc 3.0" etc.), but in practice at least varargs are passed in consecutive memory (modulo padding needed for alignment) usually on the stack or possibly in other "standard" (for the platform/architecture) places like the VAX AP-addressed arglist or S/370 R1->caller memory. For _some_ functions, some or even all of these arguments are pointers, e.g. the *scanf family and in Unix/POSIX execl*. The latter are terminated by a null pointer; the former are not. For other functions, like *printf, (most of) the arguments are not pointers at all. There is an important distinction however between a function which actually takes variable arguments, and a function which takes a va_list (or pointer thereto), which is a single, fixed, but opaque and implementation-dependent type that allows the callee to access the variable-arguments of the _caller_. > > No. You pass a controlling argument which is parsed and interpreted by the > > called function. In my previous example it was simply a count value. > > Usually but not necessarily. What is absolutely true is that the called function must (be able to) determine the number and type(s) of arguments somehow _before_ accessing them -- no checking or conversion is provided by the varargs mechanism. This _may_ be the format specifier substrings in *printf/*scanf, a null or other sentinel value as in execl*, a count, or anything else you care to code that works for your data. It _could_ be global/shared data, or a callback function, or something even more bizarre, although if you do such things don't expect anyone else to accept or reuse your code. > > Inband-terminated arrays are used to pass arrays in C. In Ada you pass the > > array bounds out of band, so you never need this data manipulation. > > Actually inband termination is mostly used in C for array of character representing a string. Arrays of other types are (more?) commonly dimensioned by counts passed explicitly or implicit in e.g. global state, and sentinel values IME rather rarer though certainly used in some cases. > > >You then pass the pointer to the list, as the last argument to the C > > >function. With the VA_* macros you then traverse the pointers and type > > >cast to whatever suitable (as in printf, you know by the format string > > >what to expect). > > > > No, this is not the way stdarg works. You access the first few arguments of > > the function and the iterativly get the next argument. There is no problem > > in causing strange errors by calling a function with the wrong number of > > arguments. The called function will reinterpret the stack as arguments or > > crash or do something much more strange. > > > To be a bit more specific: The callee accesses all fixed arguments (parameters) as normal, and the variable arguments iteratively using a va_list whose initialization (by va_start) requires specifying the last fixed parameter (which must not be of a type that gets automatically "adjusted") -- in practice this (always?) accesses varargs which are passed in consecutive memory either just after that last fixed argument or in a location determined by the calling mechanism independent of the fixed argument(s), and the va_list is really just a pointer that scans across that memory, but that mechanism is not required. Yes, if the callee does try to "receive" argument types that don't match those the caller actually passed, except for a few minor variations allowed by the default argument promotions and (arguably) type compatibility rules, you get Undefined Behavior (= Ada erroneous) which will typically do something Weird or Very Bad or both. A vararg-callee can further pass its varargs (or a suffix of them) as a block to lower-level routines, by passing the va_list. It is not defined whether va_list is an array type, and thus is effectively passed by reference and shared rather than by value, so if you need copy semantics -- that is you need to access the varargs in both the direct-callee and a further-callee -- in C89 you can and theoretically must create and destroy (va_end) separate or disjoint va_list's, although in practice just copying the va_list works, and C99 makes this official (va_copy). For example, printf can be implemented by just passing its arguments to vprintf (or perhaps vfprintf) which does the actual work; you can write your own vararg function which includes (modified) printf semantics that also calls vprintf etc. etc. (Aside: saying that there is 'no problem' with something normally connotes that it is OK, good, satisfactory, manageable. I assume you meant "there is no difficulty in causing (trouble)", but it is simpler and IMO clearer to use the positive "it is easy to cause (trouble)".) -- - David.Thompson 1 now at worldnet.att.net