关于linux下iconv编码转换

文章目录

libiconv 下载

网站链接:

https://savannah.gnu.org/projects/libiconv/

http://www.gnu.org/software/libiconv/

iconv函数

/* Convert at most *INBYTESLEFT bytes from *INBUF according to the
   code conversion algorithm specified by CD and place up to
   *OUTBYTESLEFT bytes in buffer at *OUTBUF.  */
extern size_t iconv (iconv_t __cd, char **__restrict __inbuf,
		     size_t *__restrict __inbytesleft,
		     char **__restrict __outbuf,
		     size_t *__restrict __outbytesleft);

注意函数参数 __inbuf__outbuf 为 二级指针, __inbytesleft__outbytesleft 是指针
函数执行后,无论是否转换成功,这四个参数的值要发生变化。它们即是输入参数也输出参数,但是意思不同。

作为入参:
第一个参数 cd 是转换句柄。
第二个参数 __inbuf是输入字符串的地址的地址。
第三个参数 __inbytesleft 是输入字符串的长度。
第四个参数 __outbuf是输出缓冲区的首地址
第五个参数 __outbytesleft是输出缓冲区的长度。

作为出参
第一个参数 cd 是转换句柄。
第二个参数 __inbuf指向剩余字符串的地址的地址。
第三个参数 __inbytesleft 是剩余字符串的长度。
第四个参数 __outbuf是输出缓冲区剩余空间的首地址的地址 。
第五个参数 __outbytesleft是输出缓冲区剩余空间的长度。

示例代码:

#include <iostream>
#include <iconv.h>
#include <cstring>
#include <fstream>

class CodeConverter {
private:
    iconv_t cd;
public:
    // 构造 from_ 原编码 to_ 目标编码
    CodeConverter(const char *from_,const char *to_) {
        cd = iconv_open(to_, from_);
    }

    // 析构
    ~CodeConverter() {
        iconv_close(cd);
    }

    // 转换输出
    /**
     * 转换编码
     * @param inbuf 待转原数据
     * @param inlen 待转原数据长度
     * @param outbuf 转换后数据
     * @param outlen 转换后长度
     * @return
     */
    int convert(char *inbuf,int inlen,char *outbuf,int outlen) {
        char **pin = &inbuf;
        char **pout = &outbuf;
        memset(outbuf,0,outlen);
        /**作为入参
        第一个参数 cd 是转换句柄。
        第二个参数 pin 是输入字符串的地址的地址。
        第三个参数 inlen 是输入字符串的长度。
        第四个参数 pout 是输出缓冲区的首地址的地址
        第五个参数 outlen 是输出缓冲区的长度。
        */
        std::cout << "Before..." << std::endl;
        printf("pin = %p\n",pin);
        printf("pout = %p\n",pout);
        printf("inbuf = %p\n",inbuf);
        printf("outbuf = %p\n",outbuf);
        printf("inlen = %d\n",inlen);
        printf("outlen = %d\n",outlen);
        int ret = iconv(cd, pin, (size_t *)&inlen, pout, (size_t *)&outlen);
        std::cout << "After..." << std::endl;
        printf("pin = %p\n",pin);
        printf("pout = %p\n",pout);
        printf("inbuf = %p\n",inbuf);
        printf("outbuf = %p\n",outbuf);
        printf("inlen = %d\n",inlen);
        printf("outlen = %d\n",outlen);
        /**作为出参
        第一个参数 cd 是转换句柄。
        第二个参数 pin 指向剩余字符串的地址的地址。 注意 剩余字符串的地址
        第三个参数 inlen 是剩余字符串的长度。 注意 剩余字符串长度
        第四个参数 pout 是输出缓冲区剩余空间的首地址的地址  注意 缓冲区剩余空间的首地址
        第五个参数 outlen 是输出缓冲区剩余空间的长度。 注意 缓冲区剩余空间的长度
        */

        return ret;
    }
};


int main() {
    std::cout << "Hello, World!" << std::endl;
    std::ifstream inFile;
    inFile.open("../test");
    int dataLen = 128;
    auto dataArray = new char[dataLen];
    inFile.read(reinterpret_cast<char *>(dataArray), dataLen );
    inFile.close();
    std::cout << "dataArray = " << dataArray << std::endl;
    std::cout << "strlen(dataArray) = " << strlen(dataArray) << std::endl;

    // gb2312-->utf-8
    CodeConverter cc = CodeConverter("gb2312","utf-8");

    int len = strlen(dataArray);
    char bufin[len+4];
    memset(bufin,0,len+4);
    for (int j = 0; j < len; ++j) {
        bufin[j] = dataArray[j];
    }
    int bufsize = 256;
    char bufout[bufsize];
    memset(bufout,0,bufsize);
    printf("bufin size = %d\n",len+4);
    printf("bufin = %p\n",bufin);
    printf("bufout = %p\n",bufout);
    int ret = cc.convert(bufin,len+4,bufout,bufsize);
    std::cout << "bufout = " << bufout << std::endl;
    std::cout << "strlen(bufout) = " <<strlen(bufout)  << std::endl;
    delete []dataArray;
    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bm5Fl7jv-1617241446769)(Pictures/iconv编码转换/A_iconv编码转换.png)]

如图可发现

inbuf: 0x9620 + 14 = 0x962C  , cc.convert(bufin,len+4,bufout,bufsize) 传入的是 len+4
outbuf: 0x9520 + 12 + 4 = 0x9530

所以值得注意的是,如果在堆上分配的空间直接调用iconv原函数(不封装)处理后,由于iconv会改变那几个参数的值,在释放前要提前保存分配的地址。

希望我的文章对于大家有帮助,由于个人能力的局限性,文中可能存在一些问题,欢迎指正、补充!

上一篇:openwrt unzip -O


下一篇:PHP报错:iconv(): Detected an illegal character in input string