iconv的输出不正确、以及内存无法正确释放(C++)

sherwoodwang 2008-07-30 08:26:19
.源码
文件名 file.cc
#include <iconv.h>
#include <iostream>
using namespace std;
int main()
{
char *x=new char [5],*y=new char [20];
for(int i=0;i!=5;++i)
x=("good")[i];
iconv_t cd =iconv_open("UCS-4","UTF-8");
size_t xx=5,yy=20;
cout<<iconv(cd,&x,&xx,&y,&yy)<<'\n';
iconv_close(cd);
if(xx!=0)return 0;
for(int i=0;i!=20-yy;++i)
cout<<(unsigned int)y[i]<<' ';
cout<<'\n';
delete [] x;
delete [] y;
return 0;
}

.环境
Fedora9
GCC4.3.0/4.3.1
glibc内置的iconv/单独安装的libiconv
上述环境一一配对试过,并保证安装正确,且支持UCS-4、UTF-8,均不能如预期执行
.故障
首先,非预期输出,且每次输出不同
此外,内存无法正确释放
.预期输出
5
0 0 0 103 0 0 0 111 0 0 0 111 0 0 0 100 0 0 0 0
.调试
[i]当前环境 Fedora9 GCC4.3.0 glibc内置的iconv

$ g++ file.cc -g
$ gdb a.out
GNU gdb Fedora (6.8-1.fc9)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
(gdb) start
Breakpoint 1 at 0x8048781: file file.cc, line 6.
Starting program: /home/<user>/a.out
main () at file.cc:6
6 char *x=new char [5],*y=new char [20];
Missing separate debuginfos, use: debuginfo-install gcc.i386 glibc.i686
(gdb) next
7 for(int i=0;i!=5;++i)
(gdb)
8 x[i]=("good")[i];
(gdb)
7 for(int i=0;i!=5;++i)
(gdb)
8 x[i]=("good")[i];
(gdb)
7 for(int i=0;i!=5;++i)
(gdb)
8 x[i]=("good")[i];
(gdb)
7 for(int i=0;i!=5;++i)
(gdb)
8 x[i]=("good")[i];
(gdb)
7 for(int i=0;i!=5;++i)
(gdb)
8 x[i]=("good")[i];
(gdb)
7 for(int i=0;i!=5;++i)
(gdb)
9 iconv_t cd =iconv_open("UCS-4","UTF-8");
(gdb) print cd==-1
$1 = false
(gdb)
10 size_t xx=5,yy=20;
(gdb)
11 cout<<iconv(cd,&x,&xx,&y,&yy)<<'\n';
(gdb)
0
12 iconv_close(cd);
(gdb)
13 if(xx!=0)return 0;
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
15 cout<<(unsigned int)y[i]<<' ';
(gdb)
14 for(int i=0;i!=20-yy;++i)
(gdb)
16 cout<<'\n';
(gdb)
4294967257 15 2 0 0 0 0 0 0 0 0 0 1 0 0 0 61 45 4294967283 4294967223
17 delete [] x;
(gdb)
*** glibc detected *** /home/<user>/a.out: munmap_chunk(): invalid pointer: 0x083fa00d ***
======= Backtrace: =========
/lib/libc.so.6[0x2c37e4]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0x1e5e41]
/usr/lib/libstdc++.so.6(_ZdaPv+0x1d)[0x1e5e9d]
/home/<user>/a.out(__gxx_personality_v0+0x277)[0x80488c3]
/lib/libc.so.6(__libc_start_main+0xe6)[0x26c5d6]
/home/<user>/a.out(__gxx_personality_v0+0x35)[0x8048681]
======= Memory map: ========
00110000-0012c000 r-xp 00000000 fd:00 311394 /lib/ld-2.8.so
0012c000-0012d000 r--p 0001c000 fd:00 311394 /lib/ld-2.8.so
0012d000-0012e000 rw-p 0001d000 fd:00 311394 /lib/ld-2.8.so
0012e000-0012f000 r-xp 0012e000 00:00 0 [vdso]
0012f000-00214000 r-xp 00000000 fd:00 1417928 /usr/lib/libstdc++.so.6.0.10
00214000-00218000 r--p 000e4000 fd:00 1417928 /usr/lib/libstdc++.so.6.0.10
00218000-00219000 rw-p 000e8000 fd:00 1417928 /usr/lib/libstdc++.so.6.0.10
00219000-0021f000 rw-p 00219000 00:00 0
0021f000-00246000 r-xp 00000000 fd:00 311409 /lib/libm-2.8.so
00246000-00247000 r--p 00026000 fd:00 311409 /lib/libm-2.8.so
00247000-00248000 rw-p 00027000 fd:00 311409 /lib/libm-2.8.so
00248000-00255000 r-xp 00000000 fd:00 311380 /lib/libgcc_s-4.3.0-20080428.so.1
00255000-00256000 rw-p 0000c000 fd:00 311380 /lib/libgcc_s-4.3.0-20080428.so.1
00256000-003b9000 r-xp 00000000 fd:00 311401 /lib/libc-2.8.so
003b9000-003bb000 r--p 00163000 fd:00 311401 /lib/libc-2.8.so
003bb000-003bc000 rw-p 00165000 fd:00 311401 /lib/libc-2.8.so
003bc000-003bf000 rw-p 003bc000 00:00 0
08048000-08049000 r-xp 00000000 fd:00 704701 /home/<user>/a.out
08049000-0804a000 rw-p 00000000 fd:00 704701 /home/<user>/a.out
083fa000-0841b000 rw-p 083fa000 00:00 0 [heap]
b7f24000-b7f27000 rw-p b7f24000 00:00 0
b7f2f000-b7f30000 rw-p b7f2f000 00:00 0
b7f30000-b7f37000 r--s 00000000 fd:00 1443159 /usr/lib/gconv/gconv-modules.cache
bfe21000-bfe36000 rw-p bffeb000 00:00 0 [stack]

Program received signal SIGABRT, Aborted.
0x0012e416 in __kernel_vsyscall ()
(gdb)
Single stepping until exit from function __kernel_vsyscall,
which has no line number information.

Program terminated with signal SIGABRT, Aborted.
The program no longer exists.
(gdb)
多谢
...全文
984 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
robinqcn 2008-08-01
  • 打赏
  • 举报
回复
man page:
[code=BatchFile] The iconv() function returns the number of characters converted in a non-reversible way during this call; reversible conversions are not counted.
In case of error, it sets errno and returns (size_t)(-1).
[/code]
fuqd273 2008-07-31
  • 打赏
  • 举报
回复
3楼的说得对。

至少看到传2级指针的时候就应该想到参数会被改变了。

[code=BatchFile]
size_t iconv(iconv_t cd,
char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft);
......

The iconv() function converts one multibyte character at a time, and for
each character conversion it increments *inbuf and decrements *inbytesleft
by the number of converted input bytes, it increments *outbuf and decre-
ments *outbytesleft by the number of converted output bytes, and it updates
the conversion state contained in cd. [/code]
robinqcn 2008-07-31
  • 打赏
  • 举报
回复

2楼的说的对, lz可能没看清楚. iconv(...)运行后不但会改变 xx, yy, 还会改变, x, y.

附代码:


#include <iconv.h>
#include <iostream>
#include <errno.h>
using namespace std;

void xprintf(const void* data, int len)
{
char * ptr = (char*)data;
printf("\n");
for( int i = 0 ; i < len ; i++ ){
printf("[%3d:%2x] ", i,(unsigned char)(ptr[i]) );
if( (i+1)%10 == 0 ){
printf("\n");
}
}
printf("\n");
}
;

int main()
{
char tmpin[] = "GOOD!";
char tmpout[20];
char * in = tmpin;
char * out = tmpout;
memset( tmpout, 0, sizeof( tmpout ) );

iconv_t cd =iconv_open("UCS-2","ASCII");

if( cd == (iconv_t)(-1) ){
return 0;
}

size_t inbytesleft = strlen(in);
size_t outbytesleft = 20;

cout << "========= Before convert:===========" << endl;
cout << "inbytesleft:" << inbytesleft << endl;
cout << "outbytesleft:" << outbytesleft << endl;
cout << "in:" << endl << "------------------------" << endl;
xprintf( in, sizeof(tmpin) );
cout << "out:" << endl << "------------------------" << endl;
xprintf( out, sizeof(tmpout) );

cout<<"converted:"<<iconv(cd,&in,&inbytesleft,&out,&outbytesleft)<<'\n';

switch ( errno ){

case E2BIG:
cout << " There is not sufficient room at *outbuf." << endl;
break;
case EILSEQ:
cout << " An invalid multibyte sequence has been encountered in the input." << endl;
break;
case EINVAL:
cout << " An incomplete multibyte sequence has been encountered in the input." << endl;
break;
}
iconv_close(cd);
cout << endl << "=========== After convert:=========== " << endl;
cout << "inbytesleft:" << inbytesleft << endl;
cout << "outbytesleft:" << outbytesleft << endl;
cout << "in:" << endl << "------------------------" << endl;
xprintf( in, sizeof(tmpin) );
cout << "out:" << endl << "------------------------" << endl;
xprintf( out, sizeof(tmpout) );
cout << "tmpin:" << endl << "------------------------" << endl;
xprintf( tmpin, sizeof(tmpin) );
cout << "tmpout:" << endl << "------------------------" << endl;
xprintf( tmpout, sizeof(tmpout) );

return 0;
}


sherwoodwang 2008-07-31
  • 打赏
  • 举报
回复
但是xx、yy并非const类型,应该是不构成错误的,并且我也确实预期它们会改变,
    if(xx!=0)return 0;
for(int i=0;i!=20-yy;++i)
cout<<(unsigned int)y[i]<<' ';

这两句就是为它们改变而准备的。而且这不会影响iconv的输出,也不会导致内存无法正确释放。
主要问题是我不能理解为什么iconv后delete会失败。而且输出竟然是随机值。而char到unsigned int的类型转换结果如何会有这么大的数字。
sherwoodwang 2008-07-31
  • 打赏
  • 举报
回复
各位大侠,多谢多谢,感激不尽,这个问题折腾了我好几天了。
我事先以为iconv只会改动*x,*y,不曾想它就连x,y也改动了,我是在想为什么要传递二级指针,原来如此。
delete的问题也解决了,因为iconv后x,y就成了悬垂指针(顺便问一句,为什么它要改变x、y呢?执行后x、y又指向那里了呢)。
对了,补充一句,在gcc4.3.x中要#include<string.h>才能用memset、strlen。
另外再问一个问题,就是man page说iconv返回值正常应该是转换的字符数,但它怎么只要成功就返回0啊。

我这两周才刚开始用Linux,不太会用,man page似乎很少有例子,gcc对语言要求也严格。
初来乍到,多多关照。
nowplaycn 2008-07-30
  • 打赏
  • 举报
回复
iconv()第4个参数的值在调用后会改变,一般用一个新的变量来代入,参见iconv的man资料。
例如,
新建变量,将其赋值为对应的参数,然后调用
iconv(cd,&x_new,&xx_new,&y_new,&yy_new);

23,116

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧