setlocale与编码转换那些事

最近项目上调查printf语句不能正常格式化字符串的问题,做下总结。

以sprintf_s函数来说明问题的现象。

int sprintf_s(
   char *buffer,
   size_t sizeOfBuffer,
   const char *format [,
      argument] ...
);

问题发生的条件

  1. 使用了setlocale
  2. format参数是utf8编码
  3. format的%是非ASC字符,已locale编码来解释的话,刚好%与前面的编码结合,被当初了一个新的文字。

例如我们出问题时,locale是".ACP",也就是ANSI(CP932),format参数是"日付%04d/%02d/%02d 時刻%02d:%02d:%02d.%03d",UTF编码如下:

00000003h: E6 97 A5 E4 BB 98 25 30 34 64 2F 25 30 32 64 2F ; 譌?莉?04d/%02d/
00000013h: 25 30 32 64 20 E6 99 82 E5 88 BB 25 30 32 64 3A ; %02d 譎ょ綾%02d:
00000023h: 25 30 32 64 3A 25 30 32 64 2E 25 30 33 64 ; %02d:%02d.%03d

其中日付对应的UTF8编码是

E6 97 A5 E4 BB 98

CP932环境下E6 97是一个独立的SJIS双字节文字【譌】。A5是一个单字节文字【?】。E4 BB是一个双字节文字【莉】,

98 与 25刚好满足SJIS双字节文字的编码要求,首字节在0x81~0x9f或者0xe0~0xef之间。所以对应print来说,第一个%s已经不存在了,自然不能被替换。

下面就来说说setlocale。

  • 影响的函数

依据https://msdn.microsoft.com/en-US/library/x99tb11d(v=vs.80).aspx,setlocale会根据设定的category不同,产生不同的影响。

LC_COLLATE

The strcoll_stricollwcscoll_wcsicollstrxfrm_strncoll_strnicoll_wcsncoll_wcsnicoll, and wcsxfrm functions.

LC_TIME

The strftime and wcsftime functions.

LC_MONETARY

Monetary-formatting information returned by the localeconv function.

//简单来讲,该类别就是用来输出本地化金融信息(如钱币符号)时用的,需要显示调用

LC_NUMERIC

Decimal-point character for the formatted output routines (such as printf), for the data-conversion routines, and for the non-monetary formatting information returned bylocaleconv.    In addition to the decimal-point character, LC_NUMERIC also sets the thousands separator and the grouping control string returned by localeconv.

//与LC_MONETARY类似,但是需要注意,Decimal-point character (小数点符号)是不需要显示调用的,在printf等函数输出浮点数时,会隐式的使用locale相关的小数点。

比如默认的locale是C,C的小时点就是.。

LC_CTYPE

The character-handling functions (except isdigitisxdigitmbstowcs, and mbtowc, which are unaffected).

不得不吐槽的是msdn关于LC_CTYPE说得不全面+不正确。mbstowcs, and mbtowc,是受LC_CTYPE影响的。

http://www.cplusplus.com/reference/clocale/setlocale/?kw=setlocale的解释貌似是正确的。

Affects character handling functions (all functions of <cctype>, except isdigit and isxdigit), and the multibyte and wide character functions.

未完待续。。。。

时间: 2024-10-13 06:26:48

setlocale与编码转换那些事的相关文章

PHP编码转换减号(连接符)无法转换问题

PHP编码转换减号(连接符)无法转换问题技术 maybe yes 发表于2015-01-23 16:03 原文链接 : http://blog.lmlphp.com/archives/67  来自 : LMLPHP后院 使 用 PHP 的 iconv 或 mb_convert_encoding 函数进行编码转换,比如将 gb2312 转换为 utf-8 编码,在出现某些特殊字符(减号,连接符)时,不能正常工作,可能会变成问号"?"或者"C".尝试了多种方法,依然不能

多线程批量转换文件编码, 从GBK, GB2312编码转换到UTF-8编码(Python)

# coding=utf-8 # author:Jeffrey Ma # version:0.1 # build 2 # created on:2015年3月31日 # description: 1. 批量转换文件编码,从GBK GB2312编码转换到UTF-8编码 # 2. 支持指定目录下所有的文件的转换,包括子目录中的文件 # 3. 支持检测原始编码,对已经是UTF-8编码的文件,不做转换 # 4. 支持只转换指定扩展名的编码 # 5. 支持多线程转换和控制台输出 # 6. 支持控制台显示线

关于raw_input输入中文时的编码转换

今日在敲代码时出现了如下问题 中文的编码出现了问题(在键盘输入中文时也会出现同样的问题),中文的编码应该是utf-8编码格式,有以下两种方式来进行编码转换: (1)decode用法:str  -> decode('the_coding_of_str') -> unicode 即写为格式:raw_input('净利润为:'.decode('utf-8').encode('gbk')) (2)encode用法:unicode -> encode('the_coding_you_want')

Linux下查看文件编码,文件编码格式转换和文件名编码转换

linux相关   2008-10-07 10:46   阅读1392   评论0   字号: 大大  中中  小小  如果你需要在Linux中 操作windows下的文件,那么你可能会经常遇到文件编码转换的问题.Windows中默认的文件格式是GBK(gb2312),而Linux一般都是 UTF-8.下面介绍一下,在Linux中如何查看文件的编码及如何进行对文件进行编码转换. 查看文件编码 在Linux中查看文件编码可以通过以下几种方式: 1.在Vim中可以直接查看文件编码 :set file

关于JS的编码转换问题

在进行JS开发过程中,尤其是在开发报表时,报表已集成到Web页面中,通过在页面传递参数至报表中时,会发现有时某些参数值,传递到报表中是显示为问号或乱码等等一系列不能正常显示的情况. 这是由于浏览器和报表服务器的编码不同,字符多次进行编码转换时出现错误导致字符的显示出现乱码,尤其是中日韩文和特殊字符更容易出现乱码问题. 以开发报表软件FineReport为例,在给报表服务器发送请求之前,对URL或者只对URL里面的参数名字和参数值,进行cjkEncode的编码,该方式兼容了各种不同的字符集,如IS

Nim-字符串编码转换

Nim中对字符串进行转码需要用到encodings模块. encodings模块: proc getCurrentEncoding():string {.raises: [],tags: [].} #检索当前系统编码,在UNIX上,总是返回"UTF-8". proc open(destEncoding = "UTF-8"; srcEncoding = "CP1252"): EncodingConverter {. raises: [Overflo

gbk转utf-8 iconv 编码转换

linux下面有时候 字符需要进行编码转换(爬虫将gbk转为utf-8编码...),一般可以选择iconv函数. 终端下面  输入 man 3 iconv 得到  iconv函数的使用方法. 个人看习惯了,msdn文档之后感觉linux下面的文档的看的不是那么爽了. 使用iconv函数进行转码,一般使用三个函数:iconv_open  . iconv  .iconv_close三个函数. iconv_t iconv_open(const char* tocode,const char* from

Windows下字符编码转换

有时候经常使用别人用Tabhost+其它的实现demo.单纯利用Tabhost该如何使用呢? 下面看例子: public class MainActivity extends TabActivity { public TabHost tabHost; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 获取对象 tabHost = getTabH

〖Python〗-- 编码转换

[字符编码与转码] 为什么要进行编码和转码 由于每个国家电脑的字符编码格式不统一(列中国:GBK),同一款软件放到不同国家的电脑上会出现乱码的情况,出现这种情况如何解决呢?! 当然由于所有国家的电脑都支持Unicode万国码,那么我们可以把Unicode为跳板,先把字符编码转换为Unicode,在把Unicode转换为另一个国家的字符编码(例韩国),则不会出现乱码的情况.当然这里只是转编码集并不是翻译成韩文不要弄混了. Python3.0进行编码转换 # __author__:"ShengXin