你能从它的 c_str() const char* 中安全地得到一个指向字符串的指针吗?

Can you safely get a pointer to a string from its c_str() const char*?

我有一个 const char 指针,我确定它来自一个字符串。例如:

std::string myString = "Hello World!";
const char* myCstring = myString.c_str();

在我的例子中,我知道 myCstring 来自一个字符串,但我无法再访问该字符串(我从函数调用中收到了 const char*,但我无法修改函数的参数列表)。

鉴于我知道 myCstring 指向现有字符串的内容,是否有任何方法可以安全地访问它所源自的父字符串的指针?例如,我可以做这样的事情吗?

std::string* hackyStringPointer = myCstring - 6; //Along with whatever pointer casting stuff may be needed

我担心的是,可能无法保证字符串的内容存储在某些或所有平台等的连续内存中

Given that I know myCstring points to contents of an existing string, is there any way to safely access the pointer of the parent string from which it originated?

不,无法从指向属于 std::string.

的字符数据的 const char* 指针获取有效的 std::string* 指针

I received the const char* from a function call, and I cannot modify the function's argument list

在这种情况下,您唯一的选择是可以将指向 std::string 本身的指针作为实际的 const char* 指针传递,但这只有在调用您的函数的任何东西不可用时才有效以任何方式解释 const char*(当然不是以空字符结尾的 C 字符串),例如:

void doSomething(void (*func)(const char*), const char *data)
{
    ...
    func(data);
    ...
}
void myFunc(const char *myCstring)
{
    std::string* hackyStringPointer = reinterpret_cast<std::string*>(myCstring);
    ...
}

...

std::string myString = "Hello World!";
doSomething(&myFunc, reinterpret_cast<char*>(&myString));

This reference

The pointer returned may be invalidated by further calls to other member functions that modify the object.

你说你从函数调用中得到了 char*,这意味着你不知道同时字符串发生了什么,对吗?如果您知道原始字符串未更改或删除(例如超出范围并因此被破坏),那么您仍然可以使用 char*.

但是您的示例代码存在多个问题。你想这样做:

std::string* hackyStringPointer = myCstring - 6;

但我想你的意思是

char* hackyStringPointer = myCstring;

第一,您不能将 char* 转换为字符串*,第二,您不想在 char* 开始之前进行转换。 char* 指向字符串的第一个字符,您可以使用它来访问直到尾随 0 字符的字符。但是你不应该在第一个或尾随的 0 字符之前或之后,因为你不知道该内存中有什么,甚至不知道它是否存在。

您无法将从 std::string::c_str() 获得的 const char* 转换为 std::string*。你不能这样做的原因是因为 c_str() returns 指向字符串数据的指针,而不是字符串对象本身。

如果您试图获取 std::string 以便您可以使用它的成员函数,那么您可以做的是将 myCstring 包装在 std::string_view 中。这是一个非复制包装器,可让您像对待 std::string 一样对待 C 字符串。为此,您需要

std::string_view sv{myCstring, std::strlen(myCstring)};
// use sv here like it was a std::string

是的(看起来),尽管我同意如果我需要这样做,这可能表明我的代码总体上需要修改。尽管如此,答案似乎是字符串指针位于 const char* which c_str() returns 之前的 4 个字处,我确实从属于字符串的 const char* 中恢复了一个 string*。

    #include <string>
    #include <iostream>
    std::string myString = "Hello World!";
    const char* myCstring = myString.c_str();
    unsigned int strPtrSize = sizeof(std::string*);
    unsigned int cStrPtrSize = sizeof(const char*);
    long strAddress = reinterpret_cast<std::size_t>(&myString);
    long cStrAddress = reinterpret_cast<std::size_t>(myCstring);
    long addressDifference = strAddress - cStrAddress;
    long estStrAddress = cStrAddress + addressDifference;
    std::string* hackyStringPointer = reinterpret_cast<std::string*>(estStrAddress);

    cout << "Size of String* " << strPtrSize << ", Size of const char*: " << cStrPtrSize << "\n";
    cout << "String Address: " << strAddress << ", C String Address: " << cStrAddress << "\n";
    cout << "Address Difference: " << addressDifference << "\n";
    cout << "Estimated String Address " << estStrAddress << "\n";
    cout << "Hacky String: " << *hackyStringPointer << "\n";

    //If any of these asserts trigger on any platform, I may need to re-evaluate my answer
    assert(addressDifference == -4);
    assert(strPtrSize == cStrPtrSize);
    assert(hackyStringPointer == &myString);

输出结果如下:

Size of String* 4, Size of const char*: 4

String Address: 15725656, C String Address: 15725660

Address Difference: -4

Estimated String Address: 15725656

Hacky String: Hello World!

到目前为止似乎有效。如果有人可以证明字符串与其 c_str() 之间的地址差异可以在同一平台上随时间变化,或者如果不能保证字符串的所有成员都驻留在连续的内存中,我将更改我的回答“否”