How to convert a TCHAR array to std::string?
Asked Answered
D

6

35

How do I convert a TCHAR array to std::string (not to std::basic_string)?

Dougherty answered 9/6, 2011 at 10:34 Comment(2)
You realize std::string is just a typedef for a std::basic_string<char>?Masters
And do you want to convert a specifically Unicode or MBCS TCHAR (i.e. really WCHAR or CHAR) into a std::string (i.e. char) always, or convert CHAR to string and WCHAR to wstring, or something else?Rubio
S
40

TCHAR is just a typedef that, depending on your compilation configuration, either defaults to char or wchar_t.

Standard Template Library supports both ASCII (with std::string) and wide character sets (with std::wstring). All you need to do is to typedef String as either std::string or std::wstring depending on your compilation configuration. To maintain flexibility you can use the following code:

#ifndef UNICODE  
  typedef std::string String; 
#else
  typedef std::wstring String; 
#endif

Now you may use String in your code and let the compiler handle the nasty parts. String will now have constructors that lets you convert TCHAR to std::string or std::wstring.

Saxophone answered 9/6, 2011 at 10:38 Comment(5)
problem is I have to call a interface which accepts std::string so i cant send std::wstring :(Dougherty
See this question for how to convert from wstring to string.Highchair
@ebyrob: The same thing Alok Save did with std::string and std::wstring you'd also have to do with std::cout and std::wcout.Janitajanith
@Janitajanith so typedef std::wcout std_tcout and std_tstring etc? I can't... get myself to facade a standard like that. Then again, I used to do it for graphics operations all the time. Why not std::basic_string<TCHAR> for the first half of the typedef of string is there a discernible difference?Ashaashamed
@Dougherty #2574334 shows conversion between std::wstring and std::string, assuming UTF-8, but there are other scenarios. Considering this is VS, I'd just try to stick to W2A() and A2W() in most cases though.Ashaashamed
W
7

My answer is late, I'll admit that, but with the answers of 'Alok Save' and some research I've found a good way! (Note: I didn't test this version a lot, so it might not work in every case, but from what I tested it should):

TCHAR t = SomeFunctionReturningTCHAR();
std::string str;

#ifndef UNICODE
    str = t;
#else
    std::wstring wStr = t;
    str = std::string(wStr.begin(), wStr.end());
#endif

std::cout << str << std::endl; //<-- should work!
Warder answered 27/7, 2015 at 21:2 Comment(1)
It works only for 7-bit ASCII, but prints garbage for other characters.Extraction
F
5

TCHAR type is char or wchar_t, depending on your project settings.

 #ifdef UNICODE
     // TCHAR type is wchar_t
 #else
     // TCHAR type is char
 #endif

So if you must use std::string instead of std::wstring, you should use a converter function. I may use wcstombs or WideCharToMultiByte.

TCHAR * text;

#ifdef UNICODE
    /*/
    // Simple C
    const size_t size = ( wcslen(text) + 1 ) * sizeof(wchar_t);
    wcstombs(&buffer[0], text, size);
    std::vector<char> buffer(size);
    /*/
    // Windows API (I would use this)
    std::vector<char> buffer;
    int size = WideCharToMultiByte(CP_UTF8, 0, text, -1, NULL, 0, NULL, NULL);
    if (size > 0) {
        buffer.resize(size);
        WideCharToMultiByte(CP_UTF8, 0, text, -1, static_cast<BYTE*>(&buffer[0]), buffer.size(), NULL, NULL);
    }
    else {
        // Error handling
    }
    //*/
    std::string string(&buffer[0]);
#else
    std::string string(text);
#endif
Fournier answered 9/6, 2011 at 10:40 Comment(2)
I tried it, got: error C2664: 'std::basic_string<_Elem,_Traits,_Ax>::basic_string(const std::basic_string<_Elem,_Traits,_Ax> &)' : cannot convert parameter 1 from 'TCHAR [50]' to 'const std::basic_string<_Elem,_Traits,_Ax> &'Toscano
@user396483: I just tried it in VS2012. Code: link.Fournier
G
5

TCHAR is either char or wchar_t, so a

typedef basic_string<TCHAR>   tstring;

is one way of doing it.

The other is to skip char altogether and just use std::wstring.

Geranium answered 9/6, 2011 at 10:43 Comment(0)
R
1

Simple!

std::string tcharToChar(TCHAR* buffer)
{
    char *charBuffer = NULL;
    std::string returnValue;
    int lengthOfbuffer = lstrlenW(buffer);
    if(buffer!=NULL)
    {
        charBuffer = (char*)calloc(lengthOfbuffer+1,sizeof(char));
    }
    else
    {
        return NULL;
    }

    for (int index = 0;
        index < lengthOfbuffer;
        index++)
    {
        char *singleCharacter = (char*)calloc(2,sizeof(char));
        singleCharacter[0] = (char)buffer[index];
        singleCharacter[1] = '\0';
        strcat(charBuffer, singleCharacter);
        free(singleCharacter );
    }
    strcat(charBuffer, "\0");
    returnValue.append(charBuffer);
    free(charBuffer);
    return returnValue;
    
}
Repository answered 11/3, 2019 at 11:59 Comment(4)
Now you have an owning raw pointer you need to clean up. Why not return a std::string instead? Edit : You also leak a ton of tiny buffers with singleCharacter. This solution is not acceptable as-is. There is no need to dynamically allocate for singleCharacter and I don't see the need for strcat to write a string character-by-character.Vanessa
i accept it was a lazy solution. i have corrected the leaks and returned a std::string. Thanks for your input.Repository
With the changes the answer isn't strictly harmful, so I removed my downvote. But it is still not a very good solution. There is no need for strcat or singleCharacter, you can just push the last character to the position index of charBuffer. You also don't need to allocate for charBufffer because std::string already has a character buffer you can use. Manual memory management has fallen heavily out of favor in modern C++ and should generally not be part of recommended solutions unless absolutely necessary.Vanessa
calloc, malloc, etc. are C memory allocation functions and are not as easy to use in C++. They do not start the lifetime of objects. new should be used instead, but even then new is also discouraged. std::vector and std::make_unique should replace the vast majority of manual memory management.Vanessa
K
0

Quick and dirty solution :

TCHAR str[256] = {};

// put something in str...


// convert to string
std::string strtmp(&str[0], &str[255]);

std::cout << strtmp << std::endl;
Khiva answered 18/11, 2019 at 15:36 Comment(2)
This will cause unexpected behaviour if the original string contains any non-ascii charactersOleate
I believe this will always produce an std::string with a length of 255 characters, even when the string contains a null terminator. std::string can contain nulls, specifically if you use the range based constructor like in this case.Vanessa

© 2022 - 2024 — McMap. All rights reserved.