34

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

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
ashmish2
  • 2,885
  • 8
  • 40
  • 54
  • 11
    You realize std::string is just a typedef for a std::basic_string? – Dark Falcon Jun 09 '11 at 10:37
  • 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? – Rup Jun 09 '11 at 10:39

6 Answers6

38

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.

M.M
  • 138,810
  • 21
  • 208
  • 365
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • 3
    problem is I have to call a interface which accepts std::string so i cant send std::wstring :( – ashmish2 Jun 09 '11 at 10:41
  • See [this question](http://stackoverflow.com/questions/4804298/c-how-to-convert-wstring-into-string/4804506#4804506) for how to convert from wstring to string. – kbjorklu Jun 09 '11 at 10:55
  • @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. – antred May 30 '14 at 12:35
  • 2
    @antred 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` for the first half of the typedef of string is there a discernible difference? –  May 30 '14 at 13:50
  • @ashmish2 http://stackoverflow.com/questions/2573834/c-convert-string-or-char-to-wstring-or-wchar-t 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. –  May 30 '14 at 13:56
6

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!
Aemmel
  • 122
  • 2
  • 6
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
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Naszta
  • 7,560
  • 2
  • 33
  • 49
  • 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> &' – john k Jan 04 '13 at 01:23
  • 1
    @user396483: I just tried it in VS2012. Code: [link](http://store.naszta.hu/main/example01.cpp). – Naszta Jan 04 '13 at 21:34
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.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
0

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;
    
}
user1567759
  • 21
  • 1
  • 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. – François Andrieux Apr 03 '19 at 12:47
  • i accept it was a lazy solution. i have corrected the leaks and returned a std::string. Thanks for your input. – user1567759 Jan 21 '21 at 07:18
  • 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. – François Andrieux Jan 21 '21 at 15:49
  • `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. – François Andrieux Jan 21 '21 at 15:52
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;
serup
  • 3,676
  • 2
  • 30
  • 34
  • This will cause unexpected behaviour if the original string contains any non-ascii characters – M.M Mar 31 '20 at 04:42
  • 1
    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. – François Andrieux Jan 21 '21 at 15:46