C中编码问题
编码介绍
在代码中我们通常不可避免的出现一些中文,这个时候我们就要考虑到中文的编码格式,如果不注意可能会导致乱码或者信息失真等问题。我们常用的中文编码有GBK,gb2312,Unicode等等。具体详细的介绍看下面几篇文章:
C语言编码转换
在C语言中,如果需要讲编码进行转换,可以使用iconv系列函数。
头文件以及常用函数:
1 2 3 4 5 6 7 8
| #include <iconv.h> typedef void* iconv_t; extern iconv_t iconv_open(const char* to_code, const char* from_code); extern size_t iconv(iconv_t cd, char** restrict inbuf, size_t* in_left_buf, char** restrict outbuf, size_t* out_left_buf); extern int iconv_close(iconv_t cd);
|
iconv_open
函数说明
此函数说明将要进行哪两种编码的转换,并返回一个转化句柄。
参数说明
- tocode:目标编码
- fromcode : 原编码
iconv
1
| extern size_t iconv(iconv_t cd, char** restrict inbuf, size_t* in_left_buf, char** restrict outbuf, size_t* out_left_buf);
|
函数说明
此函数用于从inbuf中读取数据并将转换到指定编码的的数据输出到outbuf中,若转换成功,则输出本次转化的字节数,否则返回sizeof_t(-1)
参数说明
- cd : 转换描述符,由iconv_open获得
- inbuf:输入缓冲区
- in_left_buf :输入缓冲区还未转换的字符数
- outbuf : 输出缓冲区
- out_len_buf:输出缓冲区的剩余空间.
iconv_close
1
| extern int iconv_close(iconv_t cd);
|
用于关闭iconv_open打开的文件描述符
举例转换函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include <iostream> #include <string> #include <iconv.h> #include <cstring> #include <errno.h> using namespace std; string convertCode(const string& p_str, const char* from, const char* to) { char * sin, * sout; int lenin, lenout, ret; const int BUF_LEN = 10240; char bufOut[BUF_LEN]; string result(""); memset(bufOut, 0x0, sizeof(bufOut)); iconv_t cd; if ((cd = iconv_open(to, from)) == (iconv_t)(-1)) { std::cout << "open iconv error" << std::endl; return ""; } lenin = p_str.length(); lenout = BUF_LEN; sin = (char*)p_str.c_str(); sout = bufOut; ret = iconv(cd, &sin, static_cast<size_t * >(&lenin), &sout, static_cast<size_t * >(&lenout)); if (-1 == ret) { std::cout << strerror(errno) << std::endl; if (errno != 84) { return ""; } } std::cout << "bufout:" << bufOut << std::endl; std::cout << "bufout end" << std::endl; iconv_close(cd); result.assign(bufOut, BUF_LEN - lenout); return result; } int main() { string s = "哈哈"; std::cout << s.length() << std::endl; s = convertCode(s, "gbk", "utf-8//IGNORE"); std::cout << s.length() << std::endl; }
|
iconv函数出现段错误的原因
使用iconv函数进行转换的时候可能会出现段错误,这里出现这个错误的主要原因是注意看iconv函数的函数原型:
1
| extern size_t iconv(iconv_t cd, char** restrict inbuf, size_t* in_left_buf, char** restrict outbuf, size_t* out_left_buf);
|
长度为size_t的指针,int指针转换为size_t指针在一些系统的转换过程会出现问题,导致长度出现错误,内存越界,出现段错误。错误信息如下:
1 2 3 4 5
| Program received signal SIGSEGV, Segmentation fault. from_gbk (irreversible=0x7fffffffb188, outend=0x61d7c0 "", outptrp=<synthetic pointer>, inend=0xa7ffffffdb76 <error: Cannot access memory at address 0xa7ffffffdb76>, inptrp=0x7fffffffb2e8, step_data=0x6157d0, step=0x615030) at ../iconv/loop.c:325 325 ../iconv/loop.c: No such file or directory.
|
size_t与int类型
size_t类型是在stddef.h文件中定义。size_t的类型与操作系统相关,在32位架构中被普遍定义为:
1
| typedef unsigned int size_t;
|
在64为机器中被定义为:
1
| typedef unsigned long size_t;
|
int类型在32和64为机器上的长度都是4位,long在32位机器为4位,在64位机器为8位。所以在64为机器上,size_t和int指针转换的过程中一定会出现问题,在32为系统中的正整数指针不会指针,但是负整数也会出现问题。