在iOS开发过程中,经常需要在Objective-C和C语言之间进行字符串的转换。Objective-C的NSString和C语言的char*、wchar_t*等类型之间转换时,需要注意编码方式和内存管理。本文将介绍几种常见的字符串声明方式以及它们之间的转换方法。
在iOS项目中,有三种方式可以声明字符串:
NSString* str = @"hello world"; // Objective-C字符串
wchar_t* str = L"hello world"; // 宽字符(Unicode)字符串,默认为UTF32
char* str = "hello world"; // ANSI字符串
如果使用L""语法声明Unicode字符串,默认编码为UTF32。使用wcslen()函数获取字符串长度时,如果输入字符串不是UTF8编码,可能会得到错误的结果。例如:
wchar_t* str1 = L"Giới thiệu về Google"; // 越南语"关于Google"
wchar_t* str2 = L"Gioi thieu ve Google"; // 简化版,仅包含ANSI字符
printf("str1 length: %d\n", wcslen(str1));
printf("str2 length: %d\n", wcslen(str2));
上述代码中,str1和str2字符数相同,但wcslen()对str1返回的长度是错误的,而对str2返回的长度是正确的。这可能是因为wcslen()对UTF32字符感到困惑,导致一些字符被多次计数。
为了确保所有C字符串都是UTF8编码,可以使用以下代码将ANSI字符串转换为UTF8宽字符串:
char* str3 = "Giới thiệu về Google";
setlocale(LC_ALL, "en_US.UTF-8");
int buflen = strlen(str3) + 1;
wchar_t* buffer = malloc(buflen * sizeof(wchar_t));
mbstowcs(buffer, str3, buflen);
printf("str3 length: %d\n", wcslen(str3));
free(buffer);
使用setlocale()确保正确的Unicode编码,wcslen()将返回正确的字符串长度。
使用NSString的built-in方法NSUTF8StringEncoding可以轻松地将NSString转换为ANSI字符串:
- (const char*)getMultiByteString {
return [self cStringUsingEncoding:NSUTF8StringEncoding];
}
返回的值在原始值有效的情况下有效,因此无需释放或释放。
将NSString转换为宽字符串(wchar_t*)稍微复杂一些:
- (wchar_t*)getWideString {
const char* temp = [self cStringUsingEncoding:NSUTF8StringEncoding];
int buflen = strlen(temp) + 1; // 包括NULL终止字符
wchar_t* buffer = malloc(buflen * sizeof(wchar_t));
mbstowcs(buffer, temp, buflen);
return buffer;
}
调用者负责释放返回的缓冲区。为了改进,可以在NSString的dealloc()方法中释放返回值。返回类型应该更改为const wchar_t*,以指示返回的值是只读的。
+ (NSString*)stringWithWideString:(const wchar_t*)ws {
int bufflen = 8 * wcslen(ws) + 1;
char* temp = malloc(bufflen);
wcstombs(temp, ws, bufflen);
NSString* retVal = [self stringWithUTF8String:temp];
free(temp);
return retVal;
}