111

I am trying to convert a standard std::string into an NSString but I'm not having much luck.

I can convert successfully from an NSString to a std::string with the following code

NSString *realm = @"Hollywood";
std::string REALM = [realm cStringUsingEncoding:[NSString defaultCStringEncoding]];

However I get a compile time error when I try the following

NSString *errorMessage = [NSString stringWithCString:REALM encoding:[NSString defaultCStringEncoding]];

The error I get is

Cannot convert 'std::string' to 'const char*' in argument passing

Am I missing something here?

cottontail
  • 10,268
  • 18
  • 50
  • 51
Anthony McCormick
  • 2,724
  • 3
  • 25
  • 27
  • 5
    It must be a typo, but you're missing '@' for string literal in 'NSString *realm = "Hollywood";' line. – Vladimir Aug 23 '10 at 22:34

6 Answers6

125

Get c-string out of std::string for conversion:

NSString *errorMessage = [NSString stringWithCString:REALM.c_str() 
                                   encoding:[NSString defaultCStringEncoding]];
Vladimir
  • 170,431
  • 36
  • 387
  • 313
  • This not seems to be a good answer, as the documentation says: /* User-dependent encoding who value is derived from user's default language and potentially other factors. The use of this encoding might sometimes be needed when interpreting user documents with unknown encodings, in the absence of other hints. This encoding should be used rarely, if at all. Note that some potential values here might result in unexpected encoding conversions of even fairly straightforward NSString content --- for instance, punctuation characters with a bidirectional encoding. */ – cyrilchampier Nov 04 '12 at 15:14
  • 36
    [NSString stringWithUTF8String:mystring.c_str()] seems more appropriate, since the std::string is more likely coming from your own code, which is likely in UTF8. – cyrilchampier Nov 04 '12 at 15:16
  • Do you guys know why on here (https://developer.apple.com/documentation/foundation/nsstring/1412128-initwithutf8string) it says “The returned object may be different from the original receiver” ? What does this mean and how would we know if it’s different ? – isJulian00 Apr 06 '19 at 01:46
  • @cyrilchapier what if our .mm file says “no specific encoding specified” ? – isJulian00 Apr 06 '19 at 01:49
58

Firstly, you've got to be using Objective-C++ for this to work in the slightest; easiest way to ensure that is rename all your *.m files to *.mm

By far the most usable (non-deprecated) manual way of getting a C++ std::string into an NSString is with:

std::string param; // <-- input
NSString* result = [NSString stringWithUTF8String:param.c_str()];
NSString* alternative = [[NSString alloc] initWithUTF8String:param.c_str()];

This will work in most cases - and if you're not doing specific encoding detection and conversion, UTF-8 is going to give you a good result for having non-latin characters 'just work.'

If you're making a bigger app, or you're not the only one working on it, however - you'll probably want something that's easier to apply.

Adapted from cocoa-dev mailing list archives

@interface NSString (cppstring_additions)
+(NSString*) stringWithwstring:(const std::wstring&)string;
+(NSString*) stringWithstring:(const std::string&)string;
-(std::wstring) getwstring;
-(std::string) getstring;
@end

@implementation NSString (cppstring_additions)

#if TARGET_RT_BIG_ENDIAN
const NSStringEncoding kEncoding_wchar_t = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF32BE);
#else
const NSStringEncoding kEncoding_wchar_t = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF32LE);
#endif

+(NSString*) stringWithwstring:(const std::wstring&)ws
{
    char* data = (char*)ws.data();
    unsigned size = ws.size() * sizeof(wchar_t);

    NSString* result = [[NSString alloc] initWithBytes:data length:size encoding:kEncoding_wchar_t];
    return result;
}
+(NSString*) stringWithstring:(const std::string&)s
{
    NSString* result = [[NSString alloc] initWithUTF8String:s.c_str()];
    return result;
}

-(std::wstring) getwstring
{
    NSData* asData = [self dataUsingEncoding:kEncoding_wchar_t];
    return std::wstring((wchar_t*)[asData bytes], [asData length] / sizeof(wchar_t));
}
-(std::string) getstring
{
    return [self UTF8String];
}

@end

With that in-place (and appropriately #imported) you can now:

NSString* result = [NSString stringWithstring:param];
string convertedBack = [result getstring];

And the same for std::wstring, which is more than handy.

rvalue
  • 2,652
  • 1
  • 25
  • 31
  • 1
    This is rad and I have used it in a couple of iphone projects. One thing I noticed was that if I was running Apple's unit test framework and I was testing a library that utilizes these methods I had to include the file containing the string conversion methods as one of the "Compile Sources" in the "Build Phases" for the unit test. Weird. – David Jul 18 '13 at 19:14
  • 1
    Yep, the unit test is essentially it's own little program, and needs to have access to the same code. Also, kudos for actually writing tests ;-) – rvalue Jul 21 '13 at 12:56
  • 1
    Do you guys know why on here (https://developer.apple.com/documentation/foundation/nsstring/1412128-initwithutf8string) it says “The returned object may be different from the original receiver” ? What does this mean and how would we know if it’s different ? – isJulian00 Apr 06 '19 at 01:46
  • 1
    @izzyMachado that kind of language in the documents typically means they reserve the "right" under the interface contract to parse, sanitize, or canonicalize the input string. i.e. it might not round-trip and still compare `==` but rather be either the "closest" or "best" representation they can make. The receiver in this case is the `NSString` class implementation, and the returned value isn't an Objective-C object, so they might also be covering that with some standard language. – rvalue Apr 07 '19 at 02:30
  • Do you know why this still works when we use initWithUTF8String and the string includes non utf8 characters , how is it still able to use the string (if it’s mint UTF-8) and print it out once it gets to be a NSString ? – isJulian00 Apr 07 '19 at 19:27
  • I don't know; but it will most likely depend on what the non-UTF8 bytes are, and if they happen to also be valid UTF codepoints. Whatever the reason, I'm pretty sure good code wouldn't rely on that; and would detect the proper encoding first - but that's really another question. – rvalue Apr 09 '19 at 00:27
26
NSString* mystring = [NSString stringWithUTF8String:stdstring.c_str()];
John Bowers
  • 1,695
  • 1
  • 16
  • 26
18

Apple now has a new way they want you to do this conversion. In XCode7, I used the Edit > Convert > To Modern Objective C Syntax... option to find this out. It uses a shorthand @ symbol.

std::string sCPPString = "Hello World!";
NSString *sAppleString = @(sCPPString.c_str());
Volomike
  • 23,743
  • 21
  • 113
  • 209
  • Sorry if it is a stupid question, But just to be sure, Is it guaranteed to make a copy of the sCPPString.c_str() into the sAppleString? I mean if sCPPString got out of score the memory inside sAppleString will still be valid? And another question about the methods stringWithUTF8String and stringWithCString, Does the first makes a copy and the other just refers to the memory buffer or both are guaranteed to make a copy too? (I know the first one makes a copy but what about the other one), I am asking just to be sure. Thanks... – MathNerd Sep 27 '20 at 19:04
4

Here is the code snippet/example:

string str_simple = "HELLO WORLD";

//string to NSString
NSString *stringinObjC = [NSString stringWithCString:str_simple.c_str()
                                encoding:[NSString defaultCStringEncoding]];            
NSLog(stringinObjC);
Deepak Kumar
  • 1,035
  • 10
  • 18
4

I've also found that:

NSString *nsString = [NSString stringWithFormat:@"%s",standardString];

Works like a champ.

BadPirate
  • 25,802
  • 10
  • 92
  • 123
  • 4
    That's pretty unsafe & not guaranteed to work. standardString if a std::string, is a C++ object. C++ objects are not safe for passing to variadic functions (variadic templates solve this problem in C++11). If it works it's a fluke & almost every compiler will at the very least warn you against doing this (if it's not an error to begin with). – Vitali Oct 08 '13 at 08:33