C语言

在讨论编码问题时,我不想首先介绍编码方式有哪些,网上的文章巨多。我想从一个编程人员的角度来看这个问题:编码为什么是我们困惑?

编码用于什么?我认为是存储。有了存储,那么就有了I/O(输入输出);编码问题复杂,就在于存储和I/O。存储是某个具体编码方式来决定,没什么复杂的。我认为复杂的是I/O,也就是在不同的存储之间转换。

I/O的本质,我认为就是流。流有字节流,有字符流。

字节流有编码问题吗?没有,一个字节序列 可以直接读从一个存储位置拷贝到另一个。对字节流,我们只关心起二进制是什么,不关心这些二进制如何组织起来表示什么样的信息。

 

字符流才是导致编码的问题所在。一个流必然牵扯两个端:发端和终端。发端把信息按一定编码方式编写成二进制留,通过一个编码转换,转换成终端可以接受的编码方式。

C/C++里的字符流,就是涉及wchar_t类型的输入输出。(wchar_t本身既是为了国际化和本地化而设计)

对于char类型的输入输出,就是简单的吧每一个字节从一个位置原封不动的传导另一个位置。

 

在C语言里,字符流的一端(prongram)就是unicode编码,另一端的编码由用户指定。处理好字符流,就要确定外部编码。

setlocale方法,程序外的一端。默认的locale是C风格的,也就是ANSCII。

 

上述论证就可以解释一切常见的问题了。

1  字节流

char * p = "1你好234";

// 这里,"1你好234"首先存储源文件里。源文件的编码确定了它的编码形式。总之编码定了后,p就是只想一串字节

setLocale(...)//这里省略setLocale的参数,是指可以随便设置locale,主要想说明,locale对字节流无影响。

fprintf(f,"%s",p)

printf("%S",p)

// 这个例子说明字节流与编码无关,只要你printf中的%s,就把对应的字节流输出,知道遇到'/0',这一点很重要!!

wprintf(f,L"%s",(wchar_t*)p);// 这就会有问题了。wprintf表示字符流,也就是一个第三个参数指定的宽字符序列(unicode)的字符流输出。系统会吧unicode转换为locale并输出。如果locale与Unicode可以转换,那没问题。否则,例如locale是C,也就是anscii编码,那么会出现错误。在本例中,wprintf返回的字节数为-1,因为'你'的Unicode无法转换为 Ansciii。注意这里-1是错误了。

那么,如果下面呢


 wchar_t * sp = L"1你";
 char * p = (char * )sp;

 FILE * fp = fopen("t1out.txt","w");
 int num = fprintf(fp,"%s",p);
 fclose(fp);

此时,num返回的是1,表明写成功,且写了1个字节。这是因为,1的unicod 为 ox0031, 你的是 ox4f60, .因为是 littel endian, 所以该字节流是ox3100604f. 那么,00意味着'/0',所以以printf %s的形式就只输出了 1。也就是 0x31

如果把"1你"改成"你1" (ox3100604f) , 则最终会输出ox0604f31. 用notepad(本地为gbk)看就是乱码。

这里fprintf等主要是对 输出 %s 来说的。 对于%d等其他形式,输出的形式均为ANSCII。

其实实际一点说,fprintf最终是对一个字节序列进行的输出或输出,最终用putchar或者getchar.

2字符流

上例其实也说明了字符流的工作方式

字符流输入输出,就是用fwprintf, wprintf之类Unicode字符流函数输出一个字符序列。而locale指定了外部的形式。

mbs2ws, ws2mbs也是这个道理。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值