An example of an API that you can't do with C stdargs

May 21, 2010

(This is a followup to yesterday's entry.)

Update: I'm actually completely wrong about this, both in practice on x86 machines with gcc and, I believe, in standards-compliant theory, as brought to my attention by nothings in comments.

One general class of impossible-in-C varargs APIs is heavily polymorphic dispatch APIs where you need to dispatch to one of several different varargs functions that have different constant arguments. Here is a gratuitous (and probably bad) API example:

void maybeLog(int what, int where, ...)

This acts as a master function that determines whether or not something gets logged to a particular output destination and then logs it if it is. Possible output destinations include standard output, some file descriptor (including standard error), or syslog, and in each case the remaining arguments are the arguments that you would pass to the respective normal output function (printf(), fprintf(), and syslog()) if you were calling it directly.

This API cannot be implemented in (standard) C because each of the output functions you want has different fixed arguments, and you cannot extract and remove the fixed arguments from the va_list in order to call one of the v* versions with the correct arguments. The only possibly prototype for this is:

void maybeLog(int what, int where, FILE *fp, int priority, char *format, ...)

(maybeLog can then call the appropriate v* function with its required fixed arguments plus the va_list; it ignores fixed arguments not needed by the output function.)

In other words, you're supplying the union of all fixed arguments potentially needed by any output function. This has several drawbacks, including the lack of extensibility if you want to add another output destination that needs a new set of fixed arguments.

(I believe that the usual approach to doing this kind of API in C is to use a preprocessor macro. This has its own problems.)

Comments on this page:

By nothings at 2010-05-21 07:33:36:

Are you sure you can't do this? As I recall, the end user documentation for this is unclear, but I've never investigated the spec or actual implementations to see...

But there's this whole va__start/va__end thing, so I'd kind of figured that if you va__start()ed, then parse off one or two things from the va__list with va__arg, and then hand the va_list off to a v* function, it would actually do what you want.

I mean, maybe it totally doesn't. I just kind of assumed it would.

(Your wiki-text documentation doesn't seem to explain how to escape an underscore, hence the excess above.)

By cks at 2010-05-21 12:04:26:

Wow, it looks like I'm totally wrong on this in practice on Intel machine with gcc (and probably with any compiler); a test program shows that manipulating the va_list with va_arg works fine and does what you expect.

In fact, the more I think about it, the more I think you have to be completely correct in general, although the Single Unix Specification stdarg page is silent on this in general except by implication. (Ah, standards. So much is implied, so little is actually stated.)

By cks at 2010-05-21 12:14:02:

The side answer: there's two ways to escape an underscore, depending on what you want to do. If you want it to come out as typewriter text, you can put it in a (( ... )) code quotation, and otherwise you have to put it in [[ ... |]]. The relative ease of (( ... )) is why all of the va_list mentions and so on in my writing are in typewriter text.

(This is documented in DWikiText in the 'Escaping Things' section, which I see I both didn't mention in the font section and then put at some distance from said section. My bad; I'll fix it at some point.)

By nothings at 2010-05-22 04:34:46:

Actually when I was posting that, I actually scrolled down and found 'escaping things'. But that didn't help.

The issue is that the ACTUAL explanation is back up earlier: "The quoting style just writes the text literally without applying any styling at all; it's what you need to use to get, for example, a non-typewriter text '*'." which I totally missed in skimming since it doesn't use the word "escaping", and because "quoting" made me think it was some kind of actual font style for quoting things so I didn't look at it more closely.

In the actual escape section, it talks about escaping "[[...]]" but looking at the second immediately above it looks as if "[[...]]" is links, which just makes the whole thing ultraconfusing. (Ah, I see, I guess it's overloaded link syntax where text with an empty link becomes escaped text. That... seems kind of random, since you do allow markup when the link is nonempty.)

And really, the real issue here is that I post dwiki text twice a year, so I never remember anything I learned the last time I did it. I understand it's important for you, but maybe comments would be better served with markdown or just plaintext or something.

Written on 21 May 2010.
« The limitations of C's varargs support
Why I'm wrong about what sort of APIs C's stdargs allows »

Page tools: View Source, View Normal, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Fri May 21 01:19:24 2010
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.