Можете ли вы безопасно получить указатель на строку из ее c_str () const char *? - PullRequest
0 голосов
/ 22 октября 2019

У меня есть указатель на константный символ, который я точно знаю, произошел из строки. Например:

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

Меня беспокоит то, что, возможно, нельзя гарантировать, что содержимое строки будет сохранено в непрерывной памяти на некоторых или на всех платформах и т. Д.

Ответы [ 4 ]

2 голосов
/ 22 октября 2019

Учитывая, что я знаю, myCstring указывает на содержимое существующей строки, есть ли способ безопасного доступа к указателю родительской строки, из которой она возникла?

Нет, естьнет способа получить действительный указатель std::string* из указателя const char* на символьные данные, принадлежащие std::string.

Я получил const char * от вызова функции, и не могуизменить список аргументов функции

Ваша единственная опция в этой ситуации будет, если вы сможете передать указатель на сам 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));
0 голосов
/ 23 октября 2019

Да (кажется), хотя я согласен с тем, что если мне нужно это сделать, это, скорее всего, признак того, что мой код нуждается в доработке в целом. Тем не менее, ответ, как представляется, заключается в том, что указатель строки находится за 4 слова до const char *, который возвращает c_str (), и я действительно восстановил строку * из const char *, принадлежащего строке.

    #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);

Вывод этого выглядит следующим образом:

Размер строки * 4, Размер константного символа *: 4

Адрес строки: 15725656, Адрес строки C: 15725660

Разница в адресе: -4

Предполагаемый адрес строки: 15725656

Строка Hacky: Hello World!

Кажется, до сих пор это работает. Если кто-то может показать, что разница адресов между строкой и ее c_str () может со временем меняться на одной и той же платформе, или если не гарантируется, что все члены строки находятся в смежной памяти, я изменю свой ответ на «Нет». . "

0 голосов
/ 22 октября 2019

Нельзя преобразовать const char*, полученное из std::string::c_str(), в std::string*. Причина, по которой вы не можете этого сделать, заключается в том, что c_str() возвращает указатель на строковые данные, а не сам строковый объект.

Если вы пытаетесь получить std::string, чтобы вы могли использовать его функции-члены, тогдачто вы можете сделать, это обернуть myCstring в std::string_view. Это не копирующая оболочка, которая позволяет вам обращаться с c-строкой как с std::string. Для этого вам понадобится что-то вроде

std::string_view sv{myCstring, std::strlen(myCstring)};
// use sv here like it was a std::string
0 голосов
/ 22 октября 2019

Эта ссылка говорит

Возвращенный указатель может быть недействительным при последующих вызовах других функций-членов, которые изменяют объект.

Вы говоритевы получили char * от вызова функции, это означает, что вы не знаете, что происходит со строкой в ​​это время, верно? Если вы знаете, что исходная строка не была изменена или удалена (например, выходит из области видимости и, следовательно, уничтожается), тогда вы все равно можете использовать символ *.

Однако в вашем примере кода есть несколько проблем. Вы хотите сделать это:

std::string* hackyStringPointer = myCstring - 6;

но я думаю, что вы имели в виду

char* hackyStringPointer = myCstring;

Во-первых, вы не можете привести символ * к строке *, а во-вторых, вы не хотите идти ДОначало символа *. Символ * указывает на первый символ строки, вы можете использовать его для доступа к символам до завершающего 0 символа. Но вам не следует идти перед первым или после завершающего символа 0, поскольку вы не знаете, что находится в этой памяти или вообще существует.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...