【问题标题】:convert std::string to LPCSTR with trailing or leading '\0'将 std::string 转换为带有尾随或前导 '\0' 的 LPCSTR
【发布时间】:2011-04-22 21:54:07
【问题描述】:

如何在保留 '\0' 字符的同时将 std::string 转换为 LPCSTR?

我想在 OPENFILENAME.lpstrFilter 上使用结果,它要求过滤器包含 '\0' 作为分隔符。

std::string.c_str() 似乎剥离和修剪 '\0'

提前致谢!

===========================

(如何正确地在回复中添加评论,例如论坛中的回复帖子?)

在阅读了您的 cmets 之后,我继续仔细检查了这个 sn-p:

std::string filter = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0";
const char* f1 = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0";
const char* f2 = filter.c_str();
for(int i = 0; i < 50; i++)
{
 char c1 = *(f1 + i); // works
 char c2 = *(f2 + i); // doesn't work. beyond the first \0, it's garbage.
}

我对 c_str() 或 LPCSTR 的工作方式有误吗?

【问题讨论】:

标签: c++ stdstring lpcstr


【解决方案1】:

一般来说,std::string 可以正确处理嵌入的 '\0' 字符。

但是,当与 const char* 交互时,必须格外小心。

在这种情况下,问题已经发生在构造字符串的过程中:

std::string filter = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; // wrong

这里你从一个 const char* 构造一个 std::string。由于构造函数不知道要使用多少个字符来构造 std::string,所以它在第一个 '\0' 处停止。

可以一个一个地复制字符,但是有一个更好的方法:使用需要两个迭代器到 char 数组的构造函数,一个带有开头,一个带有结尾:

const char filter_[] = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; 
std::string filter(filter_, filter_ + sizeof(filter_));

它看起来很糟糕,但希望你不会在代码中经常这样做。

更新:或使用 begin() 和 end() 模板的适当定义(根据 James Kanze 的评论):

const char filter_[] = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0"; 
std::string filter(begin(filter_), end(filter_));

【讨论】:

  • 这是 sizeof(filter_) - 1 如果字符串常量已经有
  • 对不起,不习惯这个接口:如果字符串常量已经包含双 \0,那就是 sizeof(filter_) - 1。使用字符串常量初始化数组会自动附加一个 '\0'。当然,这种 sizeof 的使用会在 char 更改为 wchar_t 时中断。最好使用常用的模板函数 begin(filter_), end(filter_),例如:std::string( begin( filter_ ), end( filter_ ) );
  • @James Kanze:感谢您指向 begin() 和 end() 模板,我还不知道它们。
  • @James Kanze:wrt the -1,我认为最后有三个 '\0' 是无害的,并且不想使答案过于复杂。我的选择是省略字符串常量末尾的第二个 '\0',并注释编译器将添加第二个。
【解决方案2】:

stringlength() 是您需要使用的,以确保包含所有字符,前提是它首先正确构建以包含嵌入的 \0 字符。

对于LPCSTR 有效,而cString 在范围内:

#include <boost/scoped_array.hpp>
#include <string>
#include <algorithm>

string source("mystring");
boost::scoped_array<char> cString(new char[source.length() + 1]);

std::copy(source.begin(), source.end(), cString.get());
cString[source.length()] = 0;

LPCSTR rawStr = cString.get();

没有 scoped_array:

#include <string>
#include <algorithm>

string source("mystring");
LPSTR rawStr = new char[source.length() + 1];

std::copy(source.begin(), source.end(), rawStr);
rawStr[source.length()] = 0;

// do the work here

delete[] rawStr;

编辑: 在您的 filter init 中,string 的构造函数仅包含直到第一个 \0 字符的数据。这是有道理的——当手头只有const char * 时,如何不停止复制数据?试试这个:

const char f3[] = "Terrain Configuration (*.tcfg)\0*.tcfg\0\0";
std::string filter(f3, sizeof(f3));

【讨论】:

  • 嗯...我可以一次复制一个字符,但希望有更快的方法。
  • @Jake - std::copy 消除了逐字节复制循环的需要。如果您删除上面的scoped_array,它可能会更清晰,只需将新直接放入rawStr。见编辑。
【解决方案3】:

C_STR 不会去除 NUL 字符。错误可能在于您构建 STD::string 的方式。

【讨论】:

  • c_str 不会剥离空值,但要小心,它返回的指针仍归字符串类所有,因此您必须确保复制内容
  • 请查看带有 sn-p 的已编辑问题。它在同一个范围内,不是吗?
  • 无论如何,Alexander 的观点是,在您的 sn-p 中,过滤器 std::string 并未使用您的完整输入进行初始化,因为构造函数将在第一个 nul 处停止读取。根据史蒂夫在下面的回答,我认为您需要使用std::string filter("Terrain Configuration (*.tcfg)\0*.tcfg\0\0", 40);
【解决方案4】:

这取决于 std::string 的进一步生命周期。

例如,您可以手动附加终端零:

std::string test("init");
test += '\0';

这会导致长度增加一。或者只是创建另一个附加零的 std::string 实例

【讨论】:

    猜你喜欢
    • 2010-11-15
    • 2012-07-07
    • 1970-01-01
    • 1970-01-01
    • 2012-07-26
    • 1970-01-01
    • 2016-01-28
    相关资源
    最近更新 更多