views:

238

answers:

2

The below example should work with Unicode strings but it doesn't.


CFStringRef aString =  CFSTR("one"); // in real life this is an Unicode string
CFStringRef formatString = CFSTR("This is %s example"); // also tried %S but without success
CFStringRef resultString = CFStringCreateWithFormat(NULL, NULL, formatString, aString);

// Here I should have a valid sentence in resultString but the current result is like aString would contain garbage.
+3  A: 

Use %@ if you want to include a CFStringRef via CFStringCreateWithFormat.

See the Format Specifiers section of Strings Programming Guide for Core Foundation.

  • %@ is for Objective C objects, OR CFTypeRef objects (CFStringRef is compatible with CFTypeRef)
  • %s is for a null-terminated array of 8-bit unsigned characters (i.e. normal C strings).
  • %S is for a null-terminated array of 16-bit Unicode characters.

A CFStringRef object is not the same as “a null-terminated array of 16-bit Unicode characters”.

Chris Johnsen
Thanks, BTW do you know a another way of keep that would still use %s - I want to reuse the same localizable string on all platforms and %@ is not part of printf specification.
Sorin Sbarnea
You might be able to make use of `CFStringGetCString` to convert `CFStringRef` objects into `char *` (which you could then use with `%s`): http://developer.apple.com/Mac/library/documentation/CoreFoundation/Reference/CFStringRef/Reference/reference.html#jumpTo_41
Chris Johnsen
Thanks again! From this I can conclude that on Mac I'm not able to work with Unicode strings in a nice and portable way. Also, now another interesting question: what kind of encoding does CFStringCreateWithFormat expects for cstrings (%s)? ... probably local system encoding but this is not specified.
Sorin Sbarnea
Well, you are using CFString already, how do you expect to be portable? You can still do `char *utf8buf,*utf8str; …; snprintf(utf8buf,bufLen,"foo: %s",utf8str)`, just like any other platform. If you need to pass the formatted string to some API that wants a CFString, just CFStringCreateWithCString to convert from `char *` to `CFStringRef`.
Chris Johnsen
The doc I linked says that the character array used by `%s` should be in the “system encoding”. This is usually MacRoman, but might vary depending on the primary language of the system.
Chris Johnsen
+1  A: 

As an answer to the comment in the other answer, I would recommend the poster to

  • generate a UTF8 string in a portable way into char*
  • and, at the last minute, convert it to CFString using CFStringCreateWithCString with kCFStringEncodingUTF8 as the encoding.

Please, please do not use %s in CFStringCreateWithFormat. Please do not rely on the "system encoding", which is MacRoman on Western European environments, but not in other languages. The concept of the system encoding is inherently brain-dead, especially in east Asian environments (which I came from) where even the characters inside ASCII code range (below 127!) is modified. Hell breaks loose if you rely on "system encoding". Fortunately, since 10.4, all of the methods which use "system encoding" are now deprecated, except %s... .

I'm sorry I write this much for this small topic, but it was a real pity a few years ago when there were many nice apps which didn't work on Japanese/Korean Macs because of just this "system encoding." Please refer to this detailed explanation which I wrote a few years ago, if you're interested.

Yuji