ICU u u_fgetfile与VS2012版本中的运行时不兼容
我正在尝试将从u_fgetfile返回的句柄传递到fseek/fread函数中 当将我的应用程序链接到调试运行库(/MTd/MDd)时,不会发生崩溃,但如果我链接到静态版本,则此简单代码会崩溃:ICU u u_fgetfile与VS2012版本中的运行时不兼容,c,visual-studio-2012,icu,visual-c++,C,Visual Studio 2012,Icu,Visual C++,我正在尝试将从u_fgetfile返回的句柄传递到fseek/fread函数中 当将我的应用程序链接到调试运行库(/MTd/MDd)时,不会发生崩溃,但如果我链接到静态版本,则此简单代码会崩溃: #include <stdio.h> #include "unicode\ustdio.h" int main() { UFILE* file; file = u_fopen("C:\\test.txt","r",NULL,"UTF-8"); fseek(u_fge
#include <stdio.h>
#include "unicode\ustdio.h"
int main()
{
UFILE* file;
file = u_fopen("C:\\test.txt","r",NULL,"UTF-8");
fseek(u_fgetfile(file),3,SEEK_SET);
}
#包括
#包括“unicode\ustdio.h”
int main()
{
UFILE*文件;
file=u_fopen(“C:\\test.txt”,“r”,NULL,“UTF-8”);
fseek(u_fgetfile(file),3,SEEK_SET);
}
现在,ICU的正式版本和我使用Visual Studio 2012构建自定义版本时都会发生这种情况(在调试或发布中构建ICU并不重要)
我唯一发现的是,文件结构中似乎有一些不匹配,但我真的不知道
编辑:
作为对这个问题的补充,这里有一个功能齐全的VS2012项目,它包含了复制程序(与上面发布的代码相同)和带有源代码和二进制文件的icu。在这里获取:第一个问题:是否可以编译和使用c++11功能(因为这样我们将有更多的工具来分析实际发生的事情) 第一件事是尝试使用以下代码查看文件结构内部:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main()
{
unsigned int size = sizeof(FILE);
FILE* file = fopen("main.c", "r");
unsigned int i = 0;
unsigned char buffer[size];
memcpy(buffer, file, size);
printf("The %u bytes at address %p are: \n", size, file);
for (i = 0; i < size; ++i) {
printf("%02X ", (unsigned int)(buffer[i]));
if ((i+1)%64 == 0) {
printf("\n");
}
}
printf("\n");
fclose(file);
return 0;
}
#包括
#包括
#包括
int main()
{
unsigned int size=sizeof(文件);
FILE*FILE=fopen(“main.c”、“r”);
无符号整数i=0;
无符号字符缓冲区[大小];
memcpy(缓冲区、文件、大小);
printf(“地址%p处的%u字节为:\n”、大小、文件);
对于(i=0;i
对于两个不同的文件以及调试库和静态库,用UFILE
替换FILE
,用u\u fopen
替换fopen
函数
它将显示文件结构的字节,也许我们将了解有关问题所在的有用信息。您的问题是由于链接到了错误的库 我用官方的ICU和VS2010复制了完全相反的结果,发布版本在调试版本崩溃时工作 问题是(IMHO)链接到调试和发布VC运行时,并在不同版本的函数之间传递文件指针。版本中来自fopen的结果在调试中传递给fseek。在区分_iob和FILEX文件(不同的_iob_条目)方面,它们似乎不兼容
将调试项目与发行版ICU链接,反之亦然,将导致此问题。在我看来,问题似乎存在于
\u lock\u文件中,其中说明:
/*
* The way the FILE (pointed to by pf) is locked depends on whether
* it is part of _iob[] or not
*/
if ( (pf >= _iob) && (pf <= (&_iob[_IOB_ENTRIES-1])) )
{
/*
* FILE lies in _iob[] so the lock lies in _locktable[].
*/
_lock( _STREAM_LOCKS + (int)(pf - _iob) );
/* We set _IOLOCKED to indicate we locked the stream */
pf->_flag |= _IOLOCKED;
}
else
/*
* Not part of _iob[]. Therefore, *pf is a _FILEX and the
* lock field of the struct is an initialized critical
* section.
*/
EnterCriticalSection( &(((_FILEX *)pf)->lock) );
关于在此之后出现的问题,在我看来,根本的问题只是在库之间共享一个文件*
,这失败了,因为它们有单独的文件*
存储区域。我觉得这有点令人困惑,但我对涉及的组件没有必要的了解(而且WindowsC运行时代码的风格也没有帮助)
因此,如果文件*
是在ICU中分配的,那么您不能在主应用程序中锁定它,反之亦然(尝试读取或查找总是需要锁定)
除非这个问题有一个非常明显的解决方案(我没有找到),否则我建议您在主应用程序中模拟u\u fgets()
(或您需要的任何其他东西)的行为。
据我所知,u\u fgets()
只需调用fread()
从文件中读取数据,然后使用ucnv\u toUnicode()
,转换器存储在UFILE
中(您可以使用u fgetConverter()
检索),将读取的数据转换为UChar*
一种似乎有效的方法是静态链接ICU。我不知道这是否是你的选择,但它似乎解决了我这边的问题
我下载了ICU的最新版本(51.2),并用编译工具进行了编译。然后,我将项目与icu-release-static-win32-vs2012
中的库相链接(链接sicuuc.lib
,sicuio.lib
,sicudt.lib
,sicuin.lib
)
现在u\u fgets()
不再导致访问冲突。当然,现在我的.exe
几乎有23MB大。问题是“icuio51.dll”(Release)与静态CRT链接!因此,它与共享CRT不共享同一个文件指针!这就是为什么它在“锁”中崩溃的原因
另一方面:`icuio51d.dll´(调试)与相同的共享CRT(msvcr110d.dll)链接,因此使用相同的共享文件*指针
这就是它在“调试”中工作而不是在“发布”中工作的原因
解决方案:您必须使用正确的设置重新编译ICU,以便始终使用“共享CRT”(/MD和/MDd)。。。
为此,您必须执行以下步骤:
打开解决方案“allinone\allinone.sln”
编辑项目“io”的属性
将“Win32”平台的“C/C++|代码生成|运行时库”从“多线程(/MT)”更改为“多线程DLL(/MD)”(x64似乎是正确的!)
重新编译您的项目
我确信您测试了这个,但只是为了完整性:u\u fopen()
和u\u fgetfile()
不要返回NULL
,不是吗?我已经测试过了,所以不是。icu和我的程序之间似乎存在某种文件结构不匹配。文件
在
中定义,这两个版本(libicu和测试应用程序)应该是相同的。你确定你的版本没有混合32位和64位版本吗?是的,它们应该是相同的,但是很明显句柄有问题。我甚至不知道这是如何工作的,当然如果我尝试链接一个64位的libi
FILE* filePointer = fopen("test.txt","r");
UFILE* file = u_finit(filePointer,NULL,"UTF-8");
fseek(filePointer,3,SEEK_SET); // <- won't crash