安全C ++ std :: string到TCHAR *转换?

时间:2014-12-23 22:49:16

标签: c++ string windows c++11 visual-studio-2013

我正在尝试将std :: string转换为TCHAR*以便在CreateFile()中使用。我已编译并运行的代码,但Visual Studio 2013提出了编译器警告:

  

警告C4996:' std :: _ Copy_impl':带有可能不安全的参数的函数调用 - 此调用依赖于调用者来检查传递的值是否正确。要禁用此警告,请使用-D_SCL_SECURE_NO_WARNINGS。请参阅有关如何使用Visual C ++' Checked Iterators'

的文档

我理解为什么我会收到警告,就像在我的代码中我使用std :: copy一样,但是如果可能的话,我不想定义D_SCL_SECURE_NO_WARNINGS,因为他们有一个观点:{{ 1}}不安全/不安全。因此,我想找到一种不会引发此警告的方法。

产生警告的代码:

std::copy

std::string filename = fileList->getFullPath(index); TCHAR *t_filename = new TCHAR[filename.size() + 1]; t_filename[filename.size()] = 0; std::copy(filename.begin(), filename.end(), t_filename); audioreader.setFile(t_filename); 在内部调用audioreader.setfile(),这就是我需要转换字符串的原因。

CreateFile()fileList是我自己写的课程的实例,但我不想改变任何一个的核心实现,因为这意味着我会这样做。需要在我的程序的其他区域中更改大量实现,其中此转换仅发生在该段代码中。我用于转换的方法是在http://www.cplusplus.com/forum/general/12245/#msg58523

找到的解决方案中找到的

我在另一个问题中看到了类似的东西(Converting string to tchar in VC++),但我无法理解如何调整答案与我合作,因为字符串的大小不是不变。我所见过的所有其他方式都涉及直接audioreader强制转换(或同样不安全的东西),据我所知,(TCHAR *)和其他窗口字符串类型的定义方式相对危险因为TCHAR可以是单字节或多字节字符,具体取决于UNICODE定义。

是否有人知道将TCHAR转换为std::string的安全可靠方式,以便在TCHAR*等函数中使用?

编辑以解决评论和答案中的问题:

关于是否定义UNICODE: VS2013中的项目是一个win32控制台应用程序,{。{1}}位于.cpp文件的顶部,包含CreateFile() - 什么是#undef UNICODEmain()之间的差异?因为我认为Amadeus所要求的下划线是重要的。

与问题没有直接关系,但可能会增加透视:此程序不会在英国境外使用,因此ANSI vs UNICODE对此无关紧要。这是创建音频服务器和客户端的个人项目的一部分。因此,您可能会看到一些引用网络通信的位。这个程序的目的是让我使用Xaudio和winsock。转换问题纯粹涉及在服务器端加载文件,因此它可以打开它并开始读取块进行传输。我正在使用c:/ windows / media

中的.wav文件进行测试

文件名编码:我使用UNICODE_UNICODE在运行时读取文件名。通过查看FindFirstFileA()结构中的FindNextFileA()来检索名称。它们存储在cFilename中(如果重要,则包含在WIN32_FIND_DATAA中),但可以更改。我认为这就是Dan Korn的意思。

有关我的课程和职能的更多信息:

以下内容分布在AudioReader.h,Audioreader.cpp,FileList.h,FileList.cpp和ClientSession.h之间。上面的片段在ClientSession.cpp中。请注意,在我的大多数文件中,我声明vector<string>

unique_ptr

3 个答案:

答案 0 :(得分:3)

问题的根源在于您混合了TCHAR和非TCHAR s。即使你让它在你的机器上工作,除非你做得恰到好处,否则当路径中使用非ASCII字符时它将会失败。

如果您可以使用std::tstring而不是常规字符串,那么您不必担心格式转换或代码页与Unicode问题。

如果没有,您可以使用转化功能,例如MultiByteToWideChar,但要确保您了解源字符串中使用的编码,否则会让事情变得更糟。

答案 1 :(得分:2)

如果您不需要支持包含UTF-8(或其他多字节编码)的字符串,那么只需使用ANSI版本的Windows API:

handle = CreateFileA( filename.c_str(), .......)

您可能需要重新设置代码,因为CreateFile已隐藏在需要TCHAR的函数中。这些天不建议;在代码中散布T版本的所有内容都很痛苦,并且它具有流动效果(例如某人建议的std::tstring - 唉!)

自1998年以来,没有必要支持来自相同源代码的双重编译.Windows API必须支持这两个版本以实现向后兼容,但您自己的代码不需要。


如果您确实要支持包含UTF-8(和this is a better idea than using UTF-16 everywhere)的字符串,则需要将其转换为UTF-16字符串才能调用Windows API。

执行此操作的常用方法是通过Windows API函数MultiByteToWideChar,这有点难以正确使用,但您可以将其包装在函数中:

std::wstring make_wstring( std::string const &s );

调用MultiByteToWideChar返回UTF-16字符串,然后使用其.c_str()函数将其传递给WinAPI函数。

See this codereview thread可能实现这样的功能(尽管答案中的注释讨论)

答案 2 :(得分:1)

请改为尝试:

std::string filename = fileList->getFullPath(index);

#ifndef UNICODE
audioreader.setFile(filename.c_str());
#else
std::wstring w_filename;
int len = MultiByteToWideChar(CP_ACP, 0, filename.c_str(), filename.length(), NULL, 0);
if (len > 0)
{
    w_filename.resize(len);
    MultiByteToWideChar(CP_ACP, 0, filename.c_str(), filename.length(), &w_filename[0], len);
}
audioreader.setFile(w_filename.c_str());
#endif

可替换地:

std::string filename = fileList->getFullPath(index);

#ifndef UNICODE
audioreader.setFile(filename.c_str());
#else
std::wstring_convert<std::codecvt<wchar_t, char, std::mbstate_t>> conv;
std::wstring w_filename = conv.from_bytes(filename);
audioreader.setFile(w_filename.c_str());
#endif