iconv 踩坑

  • 看看 code_convert1 方法的坑在哪里
std::string code_convert1(const char* from_charset, const char* to_charset, const std::string& instr)
{
    if (instr.empty()) return "";

    iconv_t cd;

    size_t inlen = instr.size();
    char* inbuf = (char*)instr.c_str();

    size_t outlen = inlen * 3 + 2;
    char* outbuf = (char*)malloc(outlen);

    std::string outstr;
    char **pin = &inbuf;
    char **pout = &outbuf;

    cd = iconv_open(to_charset, from_charset);
    if (cd == 0) return "";
    memset(outbuf, 0, outlen);
    size_t oldOutLen = outlen;

    size_t ret = iconv(cd, pin, &inlen, pout, &outlen);
    if (ret == 0) outstr.append(outbuf);//这里的值是错的
    iconv_close(cd);
    free(outbuf);//执行到此处时,程序会崩溃

    return outstr;
}

程序执行到 free(outbuf) 这行的时候,发生崩溃,原因是在 iconv() 这个方法内部, pout 的值发生了改变,导致 outbuf 指向的地址发生变化,不再指向最初分配的空间地址了,所以需要增加一个临时变量,用来保存最初分配的空间地址,下面是正确的写法。

  • 正确写法 code_convert2

std::string code_convert2(const char* from_charset, const char* to_charset, const std::string& instr)
{
    if (instr.empty()) return "";

    iconv_t cd;

    size_t inlen = instr.size();
    char* inbuf = (char*)instr.c_str();

    size_t outlen = inlen * 3 + 2;
    char* outbuf = (char*)malloc(outlen);
    char* pFreeOut = outbuf;//用这个变量保存最初分配的空间地址

    std::string outstr;
    char **pin = &inbuf;
    char **pout = &outbuf;

    cd = iconv_open(to_charset, from_charset);
    if (cd == 0) return "";
    memset(outbuf, 0, outlen);
    size_t oldOutLen = outlen;

    size_t ret = iconv(cd, pin, &inlen, pout, &outlen);
    if (ret == 0) outstr.append(pFreeOut);//这里的值是正确的
    iconv_close(cd);
    free(pFreeOut);//这里再释放就正确了

    return outstr;
}

测试代码

#pragma comment(lib,"libiconv.lib")
int main()
{
    std::string ret;
    std::string ins = "test";
    //ret = code_convert1("utf-8", "gbk", ins);
    ret = code_convert2("utf-8", "gbk", ins);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/leon528/article/details/81504486