You have discovered a curious "feature" of formatting in Objective-C and should visit Apple's Feedback Assistant and report it.
So what is going on? Well it is nothing to do with variadic functions at all, and nothing to do with NSLogv per se. Rather it is to do with the underlying Objective-C formatting code which NSLog, NSLogv, stringWithFormat:, et al use and the type of the format string itself...
Here is a simple demonstration of the "feature":
- (void)demo
{
char *sample = "АБВГ"; // This will be UTF-8 encoded
// use %p to show address, %s to show string, \n as printf doesn't add one
char *cFormat = "%p - %s\n";
NSString *nsFormat = @"%p - %s\n"; // produces an __NSCFConstantString
NSString *convertedFormat = [NSString stringWithUTF8String:cFormat]; // produces an __NSCFString
printf(cFormat, sample, sample); // works
NSLog(convertedFormat, sample, sample); // fails with __NSCFString
NSLog(nsFormat, sample, sample); // works with __NSCFConstantString
NSLog(@"formats equal: %s", [convertedFormat isEqualToString:nsFormat] ? "yes" : "no"); // __NSCFString & __NSCFConstantString are equal
}
Run that and the console will show something like:
0x1000013f8 - АБВГ
2019-10-01 10:25:48.222537+0100 demo[8435:1431874] 0x1000013f8 - –ê–ë–í–ì
2019-10-01 10:25:48.222560+0100 demo[8435:1431874] 0x1000013f8 - АБВГ
2019-10-01 10:25:48.222582+0100 demo[8435:1431874] formats equal: yes
So the C library printf works, NSLog with a constant NSString format works, but NSLog with NSString format converted from a char * does not, and yet the latter two formats compare equal... Notice also that in the failing case NSLog adds an extra newline.
The bad output, –ê–ë–í–ì, is the same interpretation of the argument string that Xcode shows for the string's memory bytes. So the underlying type of the format string is determining how the underlying bytes of the argument string are interpreted...
Such a curious "feature" makes one wonder whether it was designed for some reason, or whether we're missing the obvious... Maybe someone else can enlighten us, but unless they do let's call this a (curious) bug!
Workaround
As the above demo shows using the C library format functions work so if you are happy with losing NSLog's preamble on each outline you can just use one of them in your function:
void MyLog(const char *format, ...)
{
va_list vargs;
va_start(vargs, format);
vprintf(format, vargs);
va_end(vargs);
}
If you wish to keep to NSLog for the output you can use one of the C library's equivalents of stringWithFormat:, here is a version of your function which dynamically allocates the required space for the formatted C string and then free's it (ARC won't do that for you!):
void MyLog(const char *format, ...)
{
va_list vargs;
va_start(vargs, format);
char *output;
vasprintf(&output, format, vargs);
NSLog(@"%s", output);
free(output);
va_end(vargs);
}
The "feature" still exists with the latest Xcode 11 and macOS Catalina Beta so please do go report it at Apple's Feedback Assistant.
HTH