在Linux C编程中使用Unicode和UTF-8
目前各种Linux发行版都支持UTF-8编码,当前系统的语言和字符编码设置保存在一些环境变量中,可以通过locale命令查看:
$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
常用汉字也都位于BMP中,所以一个汉字的存储通常占3个字节。
例如编辑一个C程序:
#include <stdio.h>
int main(void)
{
 printf("你好/n");
 return 0;
}
源文件是以UTF-8编码存储的:
$ od -tc nihao.c
0000000   #   i   n   c   l   u   d   e       <   s   t   d   i   o   .
0000020   h   >  /n  /n   i   n   t       m   a   i   n   (   v   o   i
0000040   d   )  /n   {  /n  /t   p   r   i   n   t   f   (   " 344 275
0000060 240 345 245 275   /   n   "   )   ;  /n  /t   r   e   t   u   r
0000100   n       0   ;  /n   }  /n
0000107
其中八进制的344 375 240(十六进制e4 bd a0)就是“你”的UTF-8编码,八进制的345 245 275(十六进制e5 a5 bd)就是“好”。
把它编译成目标文件,"你好/n"这个字符串就成了这样一串字节:e4 bd a0 e5 a5 bd 0a 00,汉字在其中仍然是UTF-8编码的,一个汉字占3个字节,这种字符在C语言中称为多字节字符(Multibyte Character)。
运行这个程序相当于把这一串字节write到当前终端的设备文件。如果当前终端的驱动程序能够识别UTF-8编码就能打印出汉字,如果当前终端的驱动程序不能识别UTF-8编码(比如一般的字符终端)就打印不出汉字。
也就是说,像这种程序,识别汉字的工作既不是由C编译器做的也不是由libc做的,C编译器原封不动地把源文件中的UTF-8编码复制到目标文件中,libc只是当作以0结尾的字符串原封不动地write给内核,识别汉字的工作是由终端的驱动程序做的。
但是仅有这种程度的汉字支持是不够的,有时候我们需要在C程序中操作字符串里的字符,比如求字符串"你好/n"中有几个汉字或字符,用strlen就不灵了,因为strlen只看结尾的0字节而不管字符串里存的是什么,求出来的是字节数7。
为了在程序中操作Unicode字符,C语言定义了宽字符(Wide Character)类型wchar_t和一些库函数。
在字符常量或字符串字面值前面加一个L就表示宽字符常量或宽字符串,
例如定义wchar_t c = L'你';,变量c的值就是汉字“你”的31位UCS编码,而L"你好/n"就相当于{L'你', L'好', L'/n', 0},wcslen函数就可以取宽字符串中的字符个数。
看下面的程序:
#include <stdio.h>
#include <locale.h>
int main(void)
{
 if (!setlocale(LC_CTYPE, ""))
 {
  fprintf(stderr, "Can't set the specified locale! "
   "Check LANG, LC_CTYPE, LC_ALL./n");
  return 1;
 }
 printf("%ls", L"你好/n");
 return 0;
}
宽字符串L"你好/n"在源代码中当然还是存成UTF-8编码的,
但编译器会把它变成4个UCS编码0x00004f60 0x0000597d 0x0000000a 0x00000000保存在目标文件中,
按小端存储就是60 4f 00 00 7d 59 00 00 0a 00 00 00 00 00 00 00,用od命令查看目标文件应该能找到这些字节。
$ gcc hihao.c
$ od -tx1 a.out
printf的%ls转换说明表示把后面的参数按宽字符串解释,不是见到0字节就结束,而是见到UCS编码为0的字符才结束,
但是要write到终端仍然需要以多字节编码输出,这样终端驱动程序才能识别,所以printf在内部把宽字符串转换成多字节字符串再write出去。
事实上,C标准并没有规定多字节字符必须以UTF-8编码,也可以使用其它的多字节编码,在运行时根据环境变量确定当前系统的编码,
所以在程序开头需要调用setlocale获取当前系统的编码设置,如果当前系统是UTF-8的,printf就把UCS编码转换成UTF-8编码的多字节字符串再write出去。
一般来说,程序在做内部计算时通常以宽字符编码,如果要存盘或者输出给别的程序,或者通过网络发给别的程序,则采用多字节编码。
关于Unicode和UTF-8本节只介绍了最基本的概念,读者可进一步参考[Unicode FAQ]。
http://www.yayu.org/book/Linux_c_study_html/bi01.html#bibli.unicodefaq

在Linux C编程中使用Unicode和UTF-8相关推荐

  1. Linux网络编程中EAGAIN错误和EINTR错误

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 在Lin ...

  2. linux网络重置报错,Linux网络编程中EAGAIN错误和EINTR错误

    在Linux环境下开发经常会碰到很多错误(设置errno),其中EAGAIN是其中比较常见的一个错误(比如用在非阻塞操作中). 从字面上来看,是提示再试一次.这个错误经常出现在当应用程序进行一些非阻塞 ...

  3. linux网络编程中端口号和ip地址转换方法

    0.字节序 网络字节序:是大端序,即:高字节放在低地址位置 比如:0x7F000101 对于一个整型,如上,我们看到的该形式,只是在大小端主机中存储的顺序是相反的. 网络序的存储方式是  7F 00 ...

  4. linux网络编程中listen函数 backlog的含义

    结论: backlog 是用来指定在TCP连接时,同时进行 3次握手建立连接的客户端数量 listen函数在一般在调用bind之后-调用accept之前调用, 它的函数原型是: #include< ...

  5. Linux网络编程中的几组类似功能的区别

    1.bzero与memset char buff[1024]; memset(buff,0,sizeof(buff));bzero(buff, sizeof(buff)); struct sockad ...

  6. Linux C编程中的段错误

    段错误(Segmentation Fault) 1. 段错误是什么 一句话来说,段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址.访问了系统保护的内存地址.访问了只 ...

  7. Linux驱动编程中EXPORT_SYMBOL()介绍

    一.查看内核驱动代码你会发现很多的函数带有EXPORT_SYMBOL()宏定义. 二.那么EXPORT_SYMBOL的作用是什么?            EXPORT_SYMBOL标签内定义的函数或者 ...

  8. Linux shell编程中read参数说明

    概述:read命令 -n(不换行) -p(提示语句) -n(字符个数) -t(等待时间) -s(不回显) 1.基本读取read命令接收标准输入(键盘)的输入,或其他文件描述符的输入(后面在说).得到输 ...

  9. 十二、Linux系统编程中man命令的使用

    一.man命令简介 man本身就是linux命令,可以使用man命令查看man的说明文档. 二.分页 man命令的8个分页: man1: 一般命令.常见的linux命令,例如ls,cd,cat等等 m ...

最新文章

  1. mounted钩子函数_vue3.0项目开发(八)新特性之响应式系统watchEffect函数
  2. TextView 的ScrollView滚动效果
  3. 理解AMD ,CMD,CommonJS规范
  4. hibernate映射简单实例
  5. VMware(虚拟机)的网络模式介绍
  6. EasyUI中Calendar日历的简单使用
  7. 接触的第二个引擎 scaleform
  8. 疫情严峻!有高校不放寒假,直接开始新学期!还有高校紧急放假,停止考试直接回家...
  9. 010 Editor 之 二进制查看修改神器
  10. 台式计算机m.2的参数,联想启天M系列
  11. 【软件project】 文档 - 银行业务管理 - 需求分析
  12. 学习记录540@SVN查看日志报错:Item is not readable
  13. jquery 获取上传图片的大小
  14. 互联网平台埋点方案对比 Mixpanel vs Heap vs GrowingIO vs MTA
  15. 程序员装机必备利器列表
  16. ISO 8583协议-银行交易的标准
  17. mysql老司机之路
  18. 开发复杂业务系统,有哪些设计思路
  19. 安卓Android源码——ipcamera-for-android
  20. ThreadX分析(一)

热门文章

  1. MySQL导入SQL文件及常用命令
  2. mysql导入sql文件,source命令
  3. Golang操作Excel的模块Excelize学习总结2-设置单元格数据
  4. server2008 mysql数据库病毒_SQL Server数据库mdf文件中了勒索病毒*.mdf.[decrypt@files.mn].ROGER...
  5. 破界!Omi生态omi-mp发布,用小程序开发生成Web
  6. 蓝牙耳机怎么连接电脑?无线耳机连接电脑的教程
  7. 5A资源网是中国最全最大的网络资源交易与买卖平台。集合了各大网盘资源交易、游戏资源交易、软件资源交易和建站资源交易等。找优质资源首选5A资源网!
  8. 打开word文档:提示此文档包含的链接可能引用了其它文件
  9. dell服务器系统蓝屏重启,R720服务器不定期蓝屏自动重启
  10. Java事务处理全解析(四)—— 成功的案例(自己实现一个线程安全的TransactionManager)