Search code examples
c++stringc-str

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


I have a const char pointer which I know for sure came from a string. For example:

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

In my case I know myCstring came from a string, but I no longer have access to that string (I received the const char* from a function call, and I cannot modify the function's argument list).

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? For example, could I do something like this?

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

My concern is that perhaps the string's contents possibly cannot be guaranteed to be stored in contiguous memory on some or all platforms, etc.


Solution

  • Yes (it seems), although I agree that if I need to do this it's likely a sign that my code needs reworking in general. Nevertheless, the answer seems to be that the string pointer resides 4 words before the const char* which c_str() returns, and I did recover a string* from a const char* belonging to a 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);
    

    The output of this is as follows:

    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!

    It seems to work so far. If someone can show that the address difference between a string and its c_str() can change over time on the same platform, or if all members of a string are not guaranteed to reside in contiguous memory, I'll change my answer to "No."