C++ STL API的差异(当我将平台从x64切换到x86时,VS2017)
我有一个简单的ReadTextFile(完整路径)函数:C++ STL API的差异(当我将平台从x64切换到x86时,VS2017),c++,visual-studio,x86,x86-64,c++17,C++,Visual Studio,X86,X86 64,C++17,我有一个简单的ReadTextFile(完整路径)函数: std::wstring CEngine::load_text_file(std::wstring &full_path) { std::wstring buffer = m_text_file_cache[full_path]; if (buffer.empty()) // Load file: { std::wifstream wif(full_path); wif.
std::wstring CEngine::load_text_file(std::wstring &full_path)
{
std::wstring buffer = m_text_file_cache[full_path];
if (buffer.empty()) // Load file:
{
std::wifstream wif(full_path);
wif.seekg(0, std::ios::end);
buffer.resize(wif.tellg()); // On Debug/Release x86: Warning C4244: 'argument': conversion from 'std::streamoff' to 'const unsigned int', possible loss of data
wif.seekg(0);
wif.read(buffer.data() , buffer.size()); // On Debug/Release x86: Error C2664: 'std::basic_istream<wchar_t,std::char_traits<wchar_t>> &std::basic_istream<wchar_t,std::char_traits<wchar_t>>::read(_Elem *,std::streamsize)': cannot convert argument 1 from 'const wchar_t *' to 'wchar_t *'
m_text_file_cache[full_path] = buffer;
}
return buffer;
}
std::wstring CEngine::load_text_文件(std::wstring&full_路径)
{
std::wstring buffer=m_text_file_cache[完整路径];
if(buffer.empty())//加载文件:
{
std::wifstream wif(完整路径);
wif.seekg(0,std::ios::end);
buffer.resize(wif.tellg());//调试/发布x86时:警告C4244:“参数”:从“std::streamoff”转换为“const unsigned int”,可能会丢失数据
wif.seekg(0);
wif.read(buffer.data(),buffer.size());//在调试/发布x86时:错误C2664:'std::basic_istream&std::basic_istream::read(_Elem*,std::streamsize)':无法将参数1从'const wchar_t*'转换为'wchar_t*'
m_text_file_cache[完整路径]=缓冲区;
}
返回缓冲区;
}
只是一个std::map缓存,用于减少磁盘I/O。忽略它m_text_file_cache
当我编译到x64(主轨道)时没有问题,但当我编译到x86(出于好奇)时,有两个问题我在代码中用注释标记:警告C4244和错误C2664。导致警告的原因是,即使在x86模式下,文件仍然(可能)大于4GB,这意味着它们的大小类型为64位。64位整数截断为32位整数,并带有编译器提供的警告<代码>静态转换到
无符号整数
修复
导致此错误的原因是x86配置可能未在C++17模式下编译,因此,data()
函数返回wchar\u t const*
,而不是C++17返回wchar\u t*
的行为。将编译器标志更改为在C++17模式下编译,您将不再需要强制转换。最好为“所有”配置设置标志,这样以后就不必手动更改这两种配置
另外,不要使用C样式转换来修复此问题,如(wchar\u t*)buffer.data()
,因为这可能会隐藏此问题,直到它在代码的后期爆发。如果您被迫为此代码使用C++17之前的版本,请选择const_cast
:
wif.read(const_cast<wchar*>(buffer.data()) , buffer.size());
wif.read(const_cast(buffer.data()),buffer.size());
(警告问题)
x86上的警告似乎是由于x86和x64上的size\u t
的定义不同:“size\u t(无符号\u int64或无符号整数,取决于目标平台)”。“size_t是64位Windows操作系统上的64位值”-。MSVC确定tellg()
返回类型为std::streamoff
(通常为long
)的类型定义
从标准的角度来看,
size\t
定义。std::string::data
返回一个const
指针,直到C++17。我想知道x64库的实现是否比x86库的实现早一点。您应该能够查看标题(或多个标题)中的数据的定义,以了解发生了什么。出现警告的原因应该是显而易见的。在32位应用程序中,字符串使用32位索引和大小,但tellg()
返回64位值,因此您将无法存储大于4GB的文件。在C++17之前,wstring::data()
不会返回非const
指针。您可以使用多种不同的方法,尝试其他不依赖32位/64位数据类型的方法。tellg
有点奇怪。它所能保证的是,您可以获得一个令牌,用于返回到流中的同一点。这可能与文件的开头有关,也可能与文件的开头无关,因此您不能指望查找到结尾,然后调用tellg
来提供文件的大小。很明显,您的目标是MSCV,seek-and-tell技巧很有效(至少现在是这样),但如果您必须将代码移植到其他地方,这可能会产生影响。@user4581301问题是我在VS IDE中无意中仅为x64而不是所有配置设置了C++17。希雷玛猜对了。我在IDE中修复了它,错误消失了。@AmitG。谢谢我是从你下面的评论中收集到的。很好,这不是我想象中的噩梦。不知道你可以在MSVC中设定标准。不要这么多地使用它,对于我这样做的情况,我仍在努力使我的公司超越MSVC 2010,在MSVC 2010中,标准合规性真的没有那么重要。与其使用const_cast
,不如使用operator[]
:wif.read(&buffer[0],buffer.size())代码>@RemyLebeau你可以,但我永远不会推荐它,因为它会产生混乱。这是对const\u cast
@Xirema的一种完全有效且符合标准的使用,您是对的。我无意中在IDE中仅为x64而不是所有配置设置了C++17。现在它有意义了;错误消失了。@Xirema那会是什么乱七八糟的事<当buffer.size()
为0时,code>operator[]
不执行边界检查,因此buffer[0]
将表示与buffer.end()相同的地址。
当buffer.size()为0时,可以安全地引用内存缓冲区的末尾,只要不取消引用它,read()
在buffer.size()时不会
为0。此外,操作符[]
在C++11和更高版本中保证返回一个有效地址,即使size()
为0(在C++11之前,它将返回一个未定义的地址,但这是可以的,因为read()
无论如何都不会访问地址)。size\u t
用于对象的大小(在内存中)。没有理由期望它可以在支持大文件的系统上保留文件偏移量。
std::wstring :: resize (size_type n);