设为首页 加入收藏

TOP

C11中的Unicode
2015-12-15 23:09:03 来源: 作者: 【 】 浏览:2
Tags:C11 Unicode

在C11(ISO/IEC 9899:2011)标准中引入了对UTF8、UTF16以及UTF32字符编码的支持。


其中,UTF8字符直接通过char来定义,字面量前缀使用u8。比如:


char c = u8'你';
const char *s = u8"你好";


而UTF16字符直接通过char16_t来定义,字面量前缀使用u。比如:


#include


char16_t c = u'你';
const char16_t *s = "你好";


而UTF32字符直接通过char32_t来定义,字面量前缀使用U。比如:


#include


char32_t c = U'你';
const char32_t *s = U"你好";



在使用char16_t以及char32_t的时候必须包含头文件。除此之外,C11标准中还添加了诸如wsprintf、wfprintf、vwprintf、wprintf等宽字符函数。不过这些函数的字符串都是const wchar_t*类型的,即宽字符指针类型。而对于Unicode字符的显示是各家平台自己实现的。在OS X以及iOS中,至今(Apple LLVM 6.0)还没完美地支持这一C11特性,但是UTF8、UTF16以及UTF32字面量都已经支持了,尽管系统本身不支持对UTF32编码格式的解析。另外,也没有包含头文件。不过,我们可以使用Foundation库自带的unichar类型来代替char16_t。另外,printf函数不支持对UTF16编码字符的打印,若要打印UTF16字符或字符串,只能用Foundation里的NSLog函数。


下面举些例子:


#include
#include


- (void)viewDidLoad
{
? ? [super viewDidLoad];
? ? // Do any additional setup after loading the view, typically from a nib.
? ?
? ? const char *s = u8"你好,世界!";
? ? printf("此UTF-8字符串为: %s\n", s);
? ?
? ? unichar ch = u'你';
? ? const unichar *us = u"好,世界!";
? ? NSLog(@"该UTF16是:%C%S", ch, us);
? ?
? ? wprintf(L"iOS does not support for printing wide-character unicodes!\n");
}


?



在NSString字符串格式中,%C对应类型为unichar(实际为unsigned short)的UTF16编码字符;%S对应类型为const unichar*,即UTF16编码的字符串。



由于OS X以及iOS所用的LLVM Clang编译器没有引入C11标准的,因此有些UTF8与UTF16字符串的标准转换函数在这些环境下均无法支持,我们只能通过Foundation库的NSString来解决。不过,如果在Linux下,我们使用GCC4.8或更高版本的话,那么就能使用标准的C11提供的转换函数了。不过在标准C语言中,printf、puts这类打印函数只支持对UTF-8编码格式的字符串的正确打印,因此我们要输出的话需要把UTF-16编码的字符串转为UTF-8。下面介绍在标准C11情况下如果操作UTF-8、UTF16字符串,它们之间的相互转换以及打印输出。


?


#include
#include


size_t UTF16StrLen(const char16_t *utf16String)
{
? ? if(utf16String == NULL)
? ? ? ? return 0;


? ? size_t index;
? ? for(index = 0; utf16String[index] != u'\0'; index++);
? ? return index;
}


size_t UTF16ToUTF8(char *mbBuffer, const char16_t *utf16String)
{
? ? if(mbBuffer == NULL || utf16String == NULL)
? ? ? ? return 0;
? ? ? ?
? ? mbstate_t state = { };
? ? ? ?
? ? size_t mbIndex = 0;
? ? for(int utf16Index = 0; utf16String[utf16Index] != u'\0'; utf16Index++)
? ? {
? ? ? ? const size_t length = c16rtomb(&mbBuffer[mbIndex], utf16String[utf16Index], &state);
? ? ? ? mbIndex += length;
? ? }
? ?
? ? mbBuffer[mbIndex] = '\0';
? ?
? ? return mbIndex;
}


int main(int argc, char *argv[])
{?
? ? char16_t ch = u'好';
? ? char chBuffer[64];
? ? mbstate_t state = { };
? ?
? ? size_t length = c16rtomb(chBuffer, ch, &state);
? ? chBuffer[length] = '\0';
? ?
? ? printf("The UTF-8 character length is: %zu, and the character is: %s\n", length, chBuffer);
? ?
? ? const char *utf8Str = u8"你好, 世界。";
? ? printf("The UTF-8 string is: %s\n", utf8Str);
? ?
? ? const char16_t *utf16Str = u"你好, 世界。";
? ? printf("The utf16 string length is: %zu\n", UTF16StrLen(utf16Str));
? ?
? ? length = UTF16ToUTF8(chBuffer, utf16Str);
? ?
? ? printf("The UTF-8 string length is: %zu, and the content is: %s\n", length, chBuffer);
? ?
? ? printf("If the converted UTF-8 string is equal to the original one? %s\n", strcmp(chBuffer, utf8Str) == 0? "YES" : "NO");
}


在上述代码中,必须被包含。因为char16_t、char32_t、mbstate_t等类型都是定义在这个头文件中的。C11标准库仅提供了基本的UTF8字符串转UTF16字符串、UTF16字符转UTF8字符串等函数。但是木有提供获取UTF16字符串长度以及如何将UTF16字符串转UTF8字符串的函数。因此,我在开头就实现这两者功能。当然,上述代码对UTF16的处理基本是将它作为老式的UCS-2编码格式,因为它是双字节固定长度的,而现代的UTF16可能是双字节也可能是四字节变长的。像Apple搞出的Emoji就是四字节长度的UTF16编码。所以,对于四字节的UTF16编码而言,其转换是否能有效工作尚不可知。


由于UTF8编码格式的字符串对ASCII是兼容的,因此我们可以直接使用C90提供的strlen等标准库对它们进行操作。


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇Linux通过AIO进行异步读文件 下一篇如何在Android Studio中导入JNI生..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: