How to get a writable C buffer from std::string?

南楼画角 提交于 2019-12-05 11:10:43

On my new job we do not use MFC - but luckily std lib and C++11 - so I've come up to the same question as c00000fd. Thanks to BitTickler's answer I came up with the idea of using the string's internal buffer for Win32-APIs via the &s[0] resp. &s.front() catch.

Using a Win32-API function that shrinks the internal string buffer

Assuming that you have a string which shall become shortened by a Win32-API function - e.g. ::PathRemoveFileSpec(path) - you may follow this approach:

std::string path( R("?(C:\TESTING\toBeCutOff)?") );
::PathRemoveFileSpec( &path.front() ); // Using the Win32-API
                                       // and the the string's internal buffer
path.resize( strlen( path.data() ) );  // adjust the string's length 
                                       // to the first \0 character
path.shrink_to_fit();                  // optional to adjust the string's
                                       // capacity - useful if you
                                       // do not plan to modify the string again

Unicode Version:

std::wstring path( LR("?(C:\TESTING\toBeCutOff)?") );
::PathRemoveFileSpec( &path.front() ); // Using the Win32-API
                                       // and the the string's internal buffer
path.resize( wcslen( path.data() ) );  // adjust the string's length 
                                       // to the first \0 character
path.shrink_to_fit();                  // optional to adjust the string's
                                       // capacity - useful if you
                                       // do not plan to modify the string again

Using a Win32-API function that extends the internal string buffer

Assuming that you have a string which shall become extended or filled by a Win32-API function - e.g. ::GetModuleFileName(NULL, path, cPath) to retrieve your executable's path - you may follow this approach:

std::string path;
path.resize(MAX_PATH);                 // adjust the internal buffer's size
                                       // to the expected (max) size of the
                                       // output-buffer of the Win32-API function
::GetModuleFileName( NULL, &path.front(), static_cast<DWORD>( path.size() ) );
                                       // Using the Win32-API
                                       // and the the string's internal buffer
path.resize( strlen( path.data() ) );  // adjust the string's length 
                                       // to the first \0 character
path.shrink_to_fit();                  // optional to adjust the string's
                                       // capacity - useful if you
                                       // do not plan to modify the string again

Unicode Version:

std::wstring path;
path.resize(MAX_PATH);                 // adjust the internal buffer's size
                                       // to the expected (max) size of the
                                       // output-buffer of the Win32-API function
::GetModuleFileName( NULL, &path.front(), static_cast<DWORD>( path.size() ) );
                                       // Using the Win32-API
                                       // and the the string's internal buffer
path.resize( wcslen( path.data() ) );  // adjust the string's length 
                                       // to the first \0 character
path.shrink_to_fit();                  // optional to adjust the string's
                                       // capacity - useful if you
                                       // do not plan to modify the string again

When you finally shrink-to-fit the string then you need just one more line of code when extending the string's internal buffer compared with the MFC alternative, when shrinking the string it has nearly the same overhead.

The advantage of the std::string approach in contrast to the CString approach is that you do not have to declare an additional C-String pointer variable, you just work with the official std::string methods and with one strlen/wcslen function. My approach shown above only works for the shrinking variant when the resulting Win32-API buffer is null-terminated, but for that very special case in which the Win32-API returns an unterminated string, then - similar to the CString::ReleaseBuffer method - you must explicitly know and specify the new string/buffer length by path.resize( newLength ) - just like path.ReleaseBuffer( newLength ) for the CString alternative.

void GetString(char * s, size_t capacity)
{
    if (nullptr != s && capacity > 5)
    {
        strcpy_s(s,capacity, "Hello");
    }
}

void FooBar()
{
    std::string ss;
    ss.resize(6);
    GetString(&ss[0], ss.size());
    std::cout << "The message is:" << ss.c_str() << std::endl;
}

As you can see, you can use the the "old school c- pointer" both for feeding strings into a legacy function as well as use it as an OUT parameter. Of course, you need to make sure, there is enough capacity in the string for it to work etc.

The accepted way to lowercase a std::string is:

#include <algorithm>
#include <string> 

std::string data = "Abc"; 
std::transform(data.begin(), data.end(), data.begin(), ::tolower);

You really can't get around iterating through each character. The original Windows API call would be doing the same character iteration internally.

If you need to get toLower() for a locale other than the standard "C" locale, you can use instead:

std::string str = "Locale-specific string";
std::locale loc("en_US.UTF8");  // desired locale goes here
const ctype<char>& ct = use_facet<ctype<char> >(loc);
std::transform(str.begin(), str.end(), str.begin(), std::bind1st(std::mem_fun(&ctype<char>::tolower), &ct));

To answer your question directly and minus any context, you can call str.c_str() to get a const char * (LPCSTR) from a std::string. You cannot directly convert a std::string to a char * (LPTSTR); this is by design and would undermine some of the very motivations for using std::string.

Depending on your requirements, you can use one or more of the following:

  1. std::string::operator[](). This function returns a character at a given index without bounds checking.

  2. std::string::at(). This function returns a character at a given index with bounds checking.

  3. std::string::data(). This functions returns an const pointer to the raw data.

  4. std::string::c_str(). This function returns the same value as std::string::data()

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!