在Visual Studio平台上的应用libiconv库进行字符集转换的范例

来源:互联网 发布:冰与火之歌世界观知乎 编辑:程序博客网 时间:2024/05/29 19:14

有网友发邮件说我的文章:《Windows 10 正确编译 iconv 的方法》对细节的说明太少,希望内容更详细一些,所以我写一篇图文并茂的博文进一步详细说明如何把linux平台的字符符转换库libiconv迁移到Linux平台以及Visual Studio 2012如何使用。这篇文章也说明了Visual C++时如何使用MinGW编译的动态库。

前言

先说说怎么把Linux系统平台的libiconv库迁移到Windows平台上来。一般情况下VC工程默认32位开发环境,引用的库必须是32位的。比较好的工具平台有CYGWIN和MSYS。CYGWIN在Windows平台上模拟一个Linux子系统,相当于Linux程序和Windows平台中间的翻译。MSYS2在编译阶段把Linux运行时与Windows运行时一一转换映射,相当于预编译。基于工作原理的角度认为,MSYS2的效率高于CYGWIN。在64位系统上运行的MSYS2默认编译出64位的库。

配置MSYS2

虽然MSYS2在64位系统上支持启动i686编译环境,但libtool对32位的兼容性确实不好。libiconv大量应用libtool进行工程设置,所以新建一个32位的Windows虚拟机是一个比较好的选择。下图是一新建好的一个Windows 10 32位系统。


msys2的官方网站是:http://www.msys2.org/。下载msys2-i686-20161025.exe安装包。它的安装过程没有特别的安装选项,安装成功后它的安装文件如下所示:

这里需要一个适用于代码编辑的文本编辑器,这里选择Notepad++。MSYS2把MSYS2的默认安装目录c:\msys32称为文件系统的根目录,把各个分区映射到根文件系统下,分区的盘符是文件系统的第一级文件夹名字。下面分别编辑/etc/pacman.d/下的3个文件:mrrorlist.mingw32、mingwlist.mingw64和mirrorlist.msys,镜像源使用清华大学的镜像源。清华大学的镜像源的URL是:https://mirrors.tuna.tsinghua.edu.cn/msys2/。改完以后运行运行命令:

pacman -Syu
第一次运行这个命令会有一个特殊的英文提示。提示内容的大意是由于pacman自身的更新,建议用户以强行结束当前控制台进程代替运行exit命令。按照提示关闭控制台进程即可。随后重新打开mingw32应用程序,再次运行上面的命令行,提示更新完毕,如下图所示:


配置开发环境

首先是是编译环境GCC。运行命令:

pacman -Syu gccpacman -Syu mingw-w64-i686-ffmpeg mingw-w64-i686-libc++

安装ffmpeg的原因是ffmpeg的依赖项非常多,包含了大部分常用的开发工具和SDK。安装libc++的原因是只有它才能启动GCC 7.2。安装GCC只能获取到GCC 6.3。下面安装一些自动构建工具:

pacman -Syu make automake autoconf autogen libtool gettext
然后安装常用工具:

pacman -Syu tar zip zlib zlib-devel
编译环境安装成功后如下图所示:

libiconv运行configure之前

libiconv库的官方网站是:https://www.gnu.org/software/libiconv/。官方目前最新版本是1.15。运行命令下载:

wget https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.15.tar.gz  
然后解压:

tar -xvf libiconv-1.15.tar.gz 
进入解压后的目录:

cd libiconv-1.15 
我实践发现,1.15版本有configure调用的两个脚本都存在2处错误,错误的位置是相同的。这个错误也有编译器版本太新,跟旧版本不兼容的原因。首先打开buld-aux目录下的ltmain.sh文件,搜索process.h,按照如下图所示,在5527行后面加入一行:
# include <process.h>

然后注释掉5536行的代码,如下图所示:


搜索_P_WAIT,定位到5906行代码,把

  rval = (int) _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
改成:

  rval = (int) spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
如下图所示:


然后打开位于libcharset/build-aux/ltmain.sh脚本文件,修改方法与过程与上面的ltmain.sh的修改相同。最后要修改srclib\lstat.c文件。这个代码文件编译器版本升级而出现语法错误,要做的修改是把第36行注释掉了。如下图所示:


配置、编译和安装

转到MSYS2控制台,运行:

./configure --prefix=/usr/local
成功如下图所示:


运行make命令编译,成功如下图所示:


运行make install,成功如下图所示:


生成的动态库位于/usr/local/bin下面,如下图所示:


把/usr/local/bin和/usr/loca/lib两个目录下的所有文件复制到Visual Studio 2012新建的test_iconv工程目录下新建的一个iconv/x86文件夹下。这个工程是一个普通的Win32 控制台工程。如下图所示:


测试工程

MSYS2生成的a文件也是coff格式的,Visual Studio 2012能够像lib文件一样识别它。把/usr/local/include下面的Iconv.h文件复制到工程目录下,设置链接选项,它刚才复制文件存放的位置加入到工程的链接属性中一个叫做附加的库目录的值里面。我写了一个测试代码,它的功能是实现UCS-2LE字符集与UTF-8字符集之间的互相转换,并使用notepad++验证。代码如下:

#include <iostream>#include <iconv.h>#include <Windows.h>#include <atlbase.h>#include <atlstr.h>void convert_to_unicode(){FILE* pfile=fopen("a.txt","r");fseek(pfile,0,SEEK_END);size_t ifrom=(size_t) ftell(pfile);size_t ifrom_old=ifrom;char * pfrom=(char*)calloc(ifrom+1,1);char * pfrom_old=pfrom;rewind(pfile);long loc=ftell(pfile);fread(pfrom,1,ifrom,pfile);fclose(pfile);pfile=NULL;const char* pcan= iconv_canonicalize("UTF-8");libiconv_t cd=libiconv_open("UCS-2LE",pcan);//int discard=1;size_t ito=ifrom*2;size_t ito_old=ito;char * pto=(char*)calloc(ito+2,1);char * pto_old=pto;wchar_t* pwto=(wchar_t*)pto;errno_t ir=(errno_t)libiconv(cd,&pfrom,&ifrom,&pto,&ito);if(!ir){pfile=fopen("a.txt","w");fseek(pfile,0,SEEK_SET);rewind(pfile);char* psign="\xFF\xFE";fwrite(psign,1,2,pfile);fwrite((void*)pto_old,1,wcslen(pwto)*2,pfile);fflush(pfile);fclose(pfile);printf("success.\n");}else{printf("fault.\n");}free(pfrom_old);free(pto_old);libiconv_close(cd);}bool ConvertCStringToUTF8(const CString strfrom,std::string& utf8){bool br=false;wchar_t* pwfrom=(wchar_t*)calloc(strfrom.GetLength()+2,2);wcscpy(pwfrom,strfrom);char* pfrom=(char*)pwfrom;char* pfrom_old=pfrom;size_t ifrom=strfrom.GetLength()*2;size_t ifrom_old=ifrom;size_t ito=ifrom;size_t ito_old=ito;char* pto=(char*)calloc(ito+2,1);char* pto_old=pto;libiconv_t cd=libiconv_open("UTF-8","UCS-2LE");errno_t ir=libiconv(cd,&pfrom,&ifrom,&pto,&ito);if(!ir){br=true;utf8=pto_old;printf("success.\n");}else{printf("fault.\n");}free(pwfrom);free(pto_old);libiconv_close(cd);return br;}bool ConvertUTF8ToCString(const char* utf8,CString& str){bool br=false;size_t ifrom=strlen(utf8);size_t ifrom_old=ifrom;char* pfrom=(char*)calloc(ifrom+1,1);char* pfrom_old=pfrom;strcpy(pfrom,utf8);size_t ito=ifrom*2;size_t ito_old=ito;char* pto=(char*)calloc(ito+2,1);char* pto_old=pto;wchar_t* pwto=(wchar_t*)pto;libiconv_t cd=libiconv_open("UCS-2LE","UTF-8");errno_t ir=(errno_t)libiconv(cd,&pfrom,&ifrom,&pto,&ito);if(!ir){br=true;str=pwto;printf("success.\n");}else{printf("fault.\n");}free(pfrom_old);free(pto_old);libiconv_close(cd);return br;}void main(){//convert_to_unicode();std::string utf8;CString ucs2le;ConvertUTF8ToCString("UTF8תUNICODE",ucs2le);ConvertCStringToUTF8(L"UNICODEתUTF8",utf8);system("pause");}

iconv函数有两个坑。

  • 第一个坑是它会修改输入参数的值的指针,但它把转换结果存在指针被修改之间指向在内存所在的地址,所以关键是在转换之前把输出缓冲区的指针存放一个副本。
  • 第二个坑是它的返回值是size_t类型,但它的返回值的含义并非转换了多少个字符,返回值的实际类型是errno_t。总体来说,-1表示出错,0表示成功。

编译成功后把libiconv的动态库复制到Visual Studio 2012的输出目录,然后启动调试,成功截图所下所示:


转载时请遵重他人的劳动成果,不要删除作者原文链接。
转载请注明来源:http://blog.csdn.net/caoshiying。谢谢合作。

示例程序下载地址:http://download.csdn.net/download/caoshiying/9949502

阅读全文
5 0
原创粉丝点击