现在的位置: 首页 > 综合 > 正文

c/c++语言printf/wprintf,wchar_t中文字符输出总结

2017年09月02日 ⁄ 综合 ⁄ 共 4376字 ⁄ 字号 评论关闭

首先给个验证均无问题的c++模板:验证环境windows 7 + vs2012; ubuntu 12.04 + g++(4.6.3); 当然也适用c语言

此c++模板编码最好为utf-8

// 注意,此文档最好采用utf-8编码
#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main()  
{
	//此语句重要,在win7 + vs2012和 ubuntu 12.04测试结果一致
	//只要打印wchar_t字符,均加此语句,至少不会出错,此语句最好在程序初始化处
	setlocale(LC_ALL, "");  
	

	// wprintf和printf最好不能同时使用.  
	// 如下使用printf同时打印了char字符串和wchar_t字符串
	// 因此只采用printf是比较好的方法
	wchar_t ws[] = L"国家"; 
	printf("printf content start: %ls\n", ws);          
	printf("content end\n");

	return 0;          
}      
  

用上面代码的原因: 

1. 从后面我的实验可以看到, 有八种组合方式, 唯独选择这么一种是有原因的.

2. wprintf 和 printf 通用会遇到莫名其妙的问题, 

3 . printf可以打印char, 使用格式为小写%s, 也可以打印wchar_t, 使用格式为%ls 或者 大写%S

4. 只要源文件编码为utf-8, 上面的代码就是跨操作系统和编译器平台的, 并且可以统一用一种方式打印char 和 wchar_t 字符串 

得出上面结论的原因见下面:


下面为比较细节的讨论。

关于编码字符集:简单理解为,ascii码表达了美国英文字符,为一字节.

为了统一世界文字编码,出了unicode,如ucs-2,ucs-4,分别为16字节和32字节

因为历史包袱,unicode不可能完全替代以前的编码,所以出了有使用性的UTF-8编码,字节大小不定。

如何快速查看一个文字编码?如“国“字的utf-8编码是什么? 简单方法是新建一文件,记事本输入“国”, 记事本另存为,选择文件编码。 然后使用如下方式打开此文件,1:使用winhex软件 2. 使用notep++,选中文字”国“,点击菜单插件->converter->ascii to hex, 3, 其它.... (在线的就算了,我看了百度两个排名前两位的网站根本不是转的UTF-8, 而是转成了ucs-2,虽然其号称是转换成UTF-8)

如下表格是使用wchar_t的总结,其中编码格式设置是通过notepad++的格式菜单进行的,如下表格的测试代码后面会贴出来。

表格解释: 

1.采用ansi编码方式,在ubuntu下会出错,另外通过g++ -Wall -finput-charset=ISO-8859-1 test.cpp 方式可以指定输入文件格式,但是这样很麻烦,因为首先要知道文件的格式是什么,在ubuntu下 通过file  test.cpp 命令可以查到,我把ISO-8859-1到ISO-8859-16都试了,文件编码格式ANSI(即ISO8859-XX)且文件中有L"国家" 类似字符,编译不会通过,或者通过-finput-charset=xxx指定文件格式编译通过后输出也不对,故太麻烦。

2.在windows下和ubuntu下都通过的方式是文件编码采用UTF-8。

3.printf和wprintf不能混用,即一个程序中使用了printf, 就不使用wprintf,反之也是,既然printf输出char 和 wchar_t字符都可以,所以统一使用printf是最佳选择。

  当然使用printf打印wchar_t时格式不一样,是%ls 或大写的%S,  例如: printf("wide char: %ls\n", ws);

4. 一旦要打印中文字符,在程序初始化时加一句setlocale(LC_ALL, ""); 否则打印中文会出错。

5. windows 对 字符串的内部编码比较统一,char的编码都成ANSI,如 char  s[] = "国家", s里存的是”国家”的ANSI编码

      wchar_t的编码都成UCS-2,如 wchar_t  ws[] = L"国家", s里存的是”国家”的UCS-2编码

    UBUNTU 对字符串的处理不是很统一,char 字符串的编码是随着文件编码格式有所变化,如文件为ansi,则ubuntu也为ansi,文件为UTF-8, 则char s[] = "国家" 里的也是            UTF-8编码。

       wchar_t 则默认采用ucs-4编码。

总结:源代码文件编码用UTF-8, 打印采用printf是跨平台(操作系统,编译器), 跨char和wchar_t的最佳解决方案之一,另外不能忘了 setlocale(LC_ALL, "");

说的再多,不如自己测试下,如下为测试代码,一共有5种case,每次注释掉其他case,留要测试的case,并按照case注释处更改文件编码方式便可, 更改编码方式采用notepad++最方便了.

#include <stdio.h>
#include <string.h> 
#include <stddef.h>
#include <wchar.h>
#include <locale.h>

// 测试运行环境:
// ubuntu 12.04 + g++ 4.6.3(或gcc,改文件后缀就行) 
// windows 7 + vs2012
// 说明,在注释中说的编码E59BBD,是按照打印结果从低字节到高字节排练,并不一定和实际
// 的编码大小端一致。

int main()  
{
	//此语句重要,在win7 + vs2012和 ubuntu 12.04测试结果一致,只要打印wchar_t字符,均加此语句,否则出错。
	setlocale(LC_ALL, "");        
				
	/******************  case 1  **********************************/	
	// 文件utf-8编码, 字符串不加L
	// ubuntu : ws是utf-8编码: 如"国":E59BBD; 打印结果:国家
	// windows: ws是ansi编码: 如"国":b9fa; 打印结果: 国家
/* 	char ws[] = "国家"; 
	char *p = (char *)ws;
	int i = 0;
	 
	printf("sizeof(ws) is %d\n", sizeof(ws));
	for (; i < sizeof(ws); i++){  
		printf("byte: %x\n", p[i]);	
	}
	printf("content start\n");   
	printf("%s\n", ws);
	printf("content end\n");  	  */  

		/******************  case 2  **********************************/	
	// 2: 文件ansi编码, 字符串不加L
	// ubuntu : ws是ansi编码,如"国":b9fa; 打印结果:无,出错
	// windows: ws是ansi编码: 如"国":b9fa; 打印结果: 国家
/*   	char ws[] = "国家";
	char *p = (char *)ws;  
	int i = 0; 
	
	//setlocale(LC_ALL, "zh_CN.UTF-8");        
	printf("sizeof(ws) is %d\n", sizeof(ws));
	for (; i < sizeof(ws); i++){
		printf("byte: %x\n", p[i]);  	  
	}
	printf("content start: %s\n", ws);  	
	printf("content end\n");  */   
	
	
  	/******************  case 3  **********************************/	
	// 3: 文件utf-8编码, 字符串加L, 必须采用wchar_t, 用char编译器报错, 用wprintf打印	 
	// ubuntu : ws是ucs-4编码,如"国":0x000056fd; 打印结果:国家
	// windows: ws是ucs-2编码: 如"国":0x56fd; 打印结果: 国家
/* 	wchar_t ws[] = L"国家";  
	char *p = (char *)ws;  
	int i = 0;      
			   
	wprintf(L"sizeof(ws) is %d\n", sizeof(ws));
	for (; i < sizeof(ws); i++){  
		wprintf(L"byte: %x\n", p[i]);	           
	}    

	wprintf(L"wprintf content start:\n");  //必须用wprintf, 且wprintf和printf不能同时使用.
	wprintf(L"%ls\n", ws);                
	wprintf(L"content end\n");    */      	
	
		/******************  case 4  **********************************/	
	// 4: 文件utf-8编码, 字符串加L, 必须采用wchar_t, 用char编译器报错, 用printf打印	
	// ubuntu : ws是ucs-4编码,如"国":0x000056fd; 打印结果:国家
	// windows: ws是ucs-2编码: 如"国":0x56fd; 打印结果: 国家
	wchar_t ws[] = L"国家"; 
	char *p = (char *)ws;       
	int i = 0;      
			  
	printf("sizeof(ws) is %d\n", sizeof(ws));
	for (; i < sizeof(ws); i++){  
		printf("byte: %x\n", p[i]);	           
	}        

	printf("printf content start:\n");  //wprintf和printf不能同时使用.
	printf("%ls\n", ws);                
	printf("content end\n");

	/******************  case 5  **********************************/		 
	// 5: 文件ansi编码, 字符串加L, 必须采用wchar_t, 用char编译器报错
	// ubuntu : 编译不通过
	// windows: ws是ucs-2编码: 如"国":0x56fd; 打印结果: 国家
/* 	wchar_t ws[] = L"国家"; // 文件ansi编码,ws是unicode编码: 如国:56fd
	char *p = (char *)ws;    
	int i = 0;    
			  
	wprintf(L"sizeof(ws) is %d\n", sizeof(ws));
	for (; i < sizeof(ws); i++){        
		wprintf(L"byte: %x\n", p[i]);	           
	}      

	wprintf(L"wprintf content start:\n");  //必须用wprintf, 且wprintf和printf不能同时使用.
	wprintf(L"%ls\n", ws);                
	wprintf(L"content end\n");   */       
	
	while(1); //方便看结果
	return 0;          
}      
  

抱歉!评论已关闭.