Dynamically creating a va_list in C ...
... seems to be impossible, from what I can find out on the web.
A va_list is a variable argument list which you can define as an argument to a function (or a method in Objective-C). A prominent example of this is vprintf (see printf and variadic functions on Wikipedia). In Apple's Cocoa library, one example is NSString's initWithFormat:arguments:.
My problem was this: I want to call this method, but I don't know at compile-time which arguments I want to pass. Instead, I create an array with arguments. Now, I thought I would be able to create a va_list from this array and pass it to initWithFormat:arguments:, but, as noted above, this is apparently not possible. So, to make a long story short, I had to conjure up my own mock-up of such a format function. I only need to deal with strings, so basically I scan for occurrences of "%@" (indicates an object in Objective-C) and replace them with the elements from the array. Not very elegant, but it works.
- (NSString *)evaluatePseudoFormat: (NSString *)format withArguments: (NSArray *)array { NSMutableString *evaluatedString = [NSMutableString stringWithString: format]; NSRange varRange, scanRange; int length = [format length]; scanRange = NSMakeRange(0, length); int index = [array count]; NSString *replacement; while ((varRange = [format rangeOfString: @"%@" options: NSBackwardsSearch range: scanRange]).length > 0 && index >= 0) { replacement = [array objectAtIndex: --index]; [evaluatedString replaceCharactersInRange: varRange withString: replacement]; length = varRange.location; scanRange = NSMakeRange(0, length); } return evaluatedString; }
Don't ask me why I search backwards. I had some complicated reason for that. After changing some things, the reason became obsolete. However, since the code works, I don't see why I should change it now. ;-)
1 Comments:
It is possible to forge a va_list. It's simply a packed array; for example, a char followed by an int would be a total of five bytes long (assuming four-byte int).
So, something like this:
union {
va_list varargs;
void *packedArray;
} myFakeArray;
void *ptr = myFakeArray.packedArray = alloca(5); //See x-man-page://alloca
*(char *)ptr = myChar;
ptr += sizeof(char);
*(int *)ptr = myInt;
vprintf("Character %c; int %i\n", myFakeArray.varargs);
The C standard doesn't actually define what a va_list is, though, so you should probably file this solution under “non-portable fragile black magic”. Thus, while the above is true of Mac OS X today, it may vary on some other OS or some future version of OS X.
Post a Comment
<< Home