如何将 std::string 传递给需要 char* 的函数? [复制]
Posted
技术标签:
【中文标题】如何将 std::string 传递给需要 char* 的函数? [复制]【英文标题】:How do I pass an std::string to a function that expects char*? [duplicate] 【发布时间】:2010-11-30 18:51:27 【问题描述】:可能重复:Can I get a non-const C string back from a C++ string?
我需要先转换它吗?我在另一篇文章中看到,如果函数需要 const char*,则可以使用 .c_str()。只是 char* 呢?
【问题讨论】:
函数要求 char* 而不是 const char* 是否有原因? ***.com/questions/1919626/…foo(reinterpret_cast<char*>(&mystring))
- 很简单!有什么问题?
@Noah:这是我们需要能够将 cmets 否决的情况之一。请删除它。它让我的脚趾甲卷曲。
这可能是您正在使用的特定示例,但我相信 winsock 库并不是那么 foobar'd(即我认为所有方法都采用 PCSTR
)如果它是示例,那么您就是玩,养成将这样的垃圾代码更改为const char*
或std::string
的习惯。
【参考方案1】:
std::vector<char> buffer(s.begin(), s.end());
foo(&buffer[0], buffer.size());
s.assign(buffer.begin(), buffer.end());
【讨论】:
虽然请注意,在实践中,有信誉的编译器确实使用string
的连续存储。至少根据标准委员会在决定保证basic_string
在 C++0x 中的连续性时进行的民意调查。 “信誉良好的编译器”定义为“任何在场的人都能想到的编译器”。
@Steve:也许吧。但是,这个问题的正确答案很可能应该是“修复const
问题”。【参考方案2】:
没有办法从保证在所有平台上工作的字符串中获取 char*,因为string
不需要使用连续存储这一简单事实。
您最安全、最便携的做法是将字符串复制到确实使用连续存储(可能是vector
)的地方,然后改用它。
vector<char> chars(my_string.begin(), my_string.end());
char* ptr = &chars[0];
如果您想变得不那么可移植且绝对不安全,您可以确认您的 string
实现确实使用了连续存储,然后可以使用这个:
&my_str[0]
但我会打任何为我工作的开发人员这样做。
编辑:
我知道目前没有已知的 STL 实现不将字符串数据存储在连续数组中,这将使&my_str[0]
安全。在即将到来的 C++0x 标准中,这也是事实(我被要求说明这一点),要求存储是连续的。
有人建议,因为如果这些事实表明我的帖子实际上是不正确的。
自己决定,但我说不。这不在当前 C++ 标准中,因此不是必需的。在实践中,我仍然会按照我建议的方式做事,并且在任何代码审查中,我都会标记任何假定底层存储是连续的代码。
考虑一下。假设有一个关于 vtable 指针的问题。有人想检查一个类并通过查看 vtable 来获取指向虚函数的指针。我会立即告诉他们不要这样做,因为没有提到 如何 在 C++ 中实现虚拟方法。我知道的每个实现都使用 vtables,我想不出更好的方法来做到这一点。多态性很可能会永远使用 vtables 来实现。这样可以直接检查 vtable 吗?
IMO 否,因为这取决于未记录的实施细节。你无法控制它,它可能随时改变。即使您期望它永远不会改变,依赖这些实现细节仍然是糟糕的工程。
自己决定。
【讨论】:
c_str()
必须返回具有连续存储的字符串。所以const_cast<char*>(my_string.c_str())
是 可移植的,但提出了const_cast
是否真的安全的问题。如果有任何疑问,vector
方式是安全的。
@aschepler:但std::string
被允许不返回指向其内部数据的指针。 (它可以返回一个指向刚刚分配/预留的某个区域的指针,以存储c_str()
的返回值,直到对字符串进行下一次更改。)因此,即使我们跳过这将调用 UB 的事实,它也可能根本不工作。
哦,我不知何故忽略了函数可能想要修改字符串内容的可能性。
@aschepler:否则为什么要使用非const
指针?【参考方案3】:
共有三种情况:
如果函数不在您的控制范围内,并且它修改了字符串,或者您没有也无法知道它是否修改了字符串:
然后,将字符串复制到临时缓冲区中,并将其传递给函数,如下所示:
void callFoo(std::string& str);
char* tmp = new char str(str.length() +1);
strncpy(tmp, str.c_str(), str.length());
foo(tmp);
// Include the following line if you want the modified value:
str = tmp;
delete [] tmp;
如果函数不在您的控制范围内,但您确定它不会修改字符串,并且不将参数作为 const 只是 API 的错误。
然后,您可以将const
强制转换并传递给函数
void callFoo(const std::string& str)
foo(const_cast<char*> str.c_str());
您可以控制该功能(更改签名不会造成过度破坏)。
在这种情况下,将函数更改为接受 string&
(如果它修改了输入缓冲区)或 const char*
或 const string&
(如果不接受)。
【讨论】:
【参考方案4】:当一个参数被声明为 char* 时,它隐含地假定该函数将作为副作用对所指向的字符串进行修改。基于此以及 c_str() 不允许修改包含的字符串这一事实,您无法将 std::string 显式传递给此类方法。
这样的事情可以通过以下方法来实现:
#include <cstdlib>
#include <string>
#include <iostream>
void modify_string(char* pz)
pz[0] = 'm';
class string_wrapper
std::string& _s;
char* _psz;
string_wrapper(const string_wrapper&);
string_wrapper& operator=(const string_wrapper&);
public:
string_wrapper(std::string& s) : _s(s), _psz(0)
virtual ~string_wrapper()
if(0 != _psz)
_s = _psz;
delete[] _psz;
operator char*()
_psz = new char[_s.length()+1];
strcpy(_psz,_s.c_str());
return _psz;
;
int main(int argc, char** argv)
using namespace std;
std::string s("This is a test");
cout << s << endl;
modify_string(string_wrapper(s));
cout << s << endl;
return 0;
【讨论】:
【参考方案5】:如果你确定char*不会被修改,可以使用const_cast去掉const。
【讨论】:
Soo Wei 是对的,但请记住,如果您在不确定是否正常的情况下这样做,您的程序可能会崩溃! 字符串不需要使用连续存储,所以这可能行不通。c_str()
应该给你一个连续的内存块——但显然是严格只读的,这就是为什么它是 const 的。该函数没有采用const char *
表示它要么写得非常糟糕,要么会修改字符串。
在将它作为参数传递之前,我会创建一个字符串(或 char*)的副本。如果不知道函数的行为,字符串对象的状态很容易变得不一致
保证 c_str() 的返回值是连续的,并且在下一次调用非常量成员函数之前一直可用,因此使用 const_cast 将起作用。【参考方案6】:
这是一个肮脏的解决方案,但我想它可以工作
std::string foo("example");
char* cpy = (char*)malloc(foo.size()+1);
memcpy(cpy, foo.c_str(), foo.size()+1);
【讨论】:
这没什么不好的。人们正在让它变得比它需要的复杂得多。好吧,使用 new 而不是 malloc,但想法保持不变。以上是关于如何将 std::string 传递给需要 char* 的函数? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Unicode 集将 std::string 传递给 CreateDirectory
传递给 std::basic_string 的分配器能否将其方法设为虚拟
将 std::string 的 xvalue 传递给采用 std::string_view 的函数