如何将 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 实现不将字符串数据存储在连续数组中,这将使&amp;my_str[0] 安全。在即将到来的 C++0x 标准中,这也是事实(我被要求说明这一点),要求存储是连续的。

有人建议,因为如果这些事实表明我的帖子实际上是不正确的。

自己决定,但我说不。这不在当前 C++ 标准中,因此不是必需的。在实践中,我仍然会按照我建议的方式做事,并且在任何代码审查中,我都会标记任何假定底层存储是连续的代码。

考虑一下。假设有一个关于 vtable 指针的问题。有人想检查一个类并通过查看 vtable 来获取指向虚函数的指针。我会立即告诉他们不要这样做,因为没有提到 如何 在 C++ 中实现虚拟方法。我知道的每个实现都使用 vtables,我想不出更好的方法来做到这一点。多态性很可能会永远使用 vtables 来实现。这样可以直接检查 vtable 吗?

IMO 否,因为这取决于未记录的实施细节。你无法控制它,它可能随时改变。即使您期望它永远不会改变,依赖这些实现细节仍然是糟糕的工程。

自己决定。

【讨论】:

c_str() 必须返回具有连续存储的字符串。所以const_cast&lt;char*&gt;(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&amp;(如果它修改了输入缓冲区)或 const char*const string&amp;(如果不接受)。

【讨论】:

【参考方案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 的函数

我可以将 std::string 传递给 DLL 吗?

将`char []`传递给接受`std :: string&`的函数是不是是一种好习惯

将 std::string_view 传递给执行 const std::string& 的 API