How to Convert a Tchar Array to Std::String

How to convert a TCHAR array to std::string?

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.

Converting a TCHAR to wstring

The code is problematic in several ways.

First, std::wstring is a string of wchar_t (aka WCHAR) while TCHAR may be either CHAR or WCHAR, depending on configuration. So either use WCHAR and std::wstring, or TCHAR and std::basic_string<TCHAR> (remembering that std::wstring is just a typedef for std::basic_string<WCHAR>).

Second, the problem is with string length. This snippet:

WCHAR path[_MAX_PATH];
std::wstring ws(&path[0], sizeof(path)/sizeof(path[0]));

will create a string of length exactly _MAX_PATH + 1, plus a terminating null (and likely with embedded nulls, C++ strings allow that). Likely not what you want.

The other one:

WCHAR path[_MAX_PATH+1]; 
...
std::wstring ws(&path[0]);

expects that path holds a null-terminated string by the time ws is constructed, and copies it into ws. If path happens to be not null-terminated, UB ensues (usually, either garbage in ws or access violation).

If your path is either null-terminated or contains _MAX_PATH-length string, I suggest using it like this:

WCHAR path[_MAX_PATH+1];
... // fill up to _MAX_PATH characters
path[_MAX_PATH] = L'0'; // ensure it is null-terminated
std::wstring ws(path); // construct from a null-terminated string

Or if you know the actual length, just pass it:

WCHAR path[_MAX_PATH];
size_t length = fill_that_path(path);
std::wstring ws(path, length); // length shouldn’t include the null terminator, if any

See the docs (it’s the same for string and wstring except of different char type).

C++ _TCHAR* to std::string

The easiest way for command line arguments is to choose whether you want them to support wide strings or not. If not, it's easy:

int main(int argc, char *argv[])

If you want them, however, things get a little bit more complicated, but not that much. MSVC has some _wmain or whatever variant, but it's non-standard. I prefer standard main signatures. You can do this:

int main() {
PWSTR cmdLine = GetCommandLineW();

int argc;
PWSTR *argv = CommandLineToArgvW(cmdLine, &argc);
}

The whole TCHAR mess is pretty annoying to deal with. It's better to just use wide strings if you want wide string support and use narrow strings if you don't. When dealing with other Windows API functions, I highly recommend everything going in and out of them be a wide string.

How concatenate a char with TCHAR array?

gen_random should get char array with at least 11 characters (10 for size + 1 for terminating null).

So it should be:

char str[10+1]; //or char str[11];
gen_random(str, 10);

in addition, the format string should be: "%s\\%hs", the first is TCHAR* type (if UNICODE defined wchar_t* if not char*) the second is always char* type.

hs, hS

String. This value is always interpreted as type LPSTR, even
when the calling application defines Unicode.

look here

Note: in Microsoft documentation:

  • LPSTR = always char*
  • LPWSTR = always wchar_t*
  • LPTSTR = TCHAR* (if UNICODE defined: wchar_t*, else: char*)

convert std::string to const tchar*

A simple approach, which will work with all C++ standards, would be

 #include <string>

#include <windows.h> // or whatever header you're using that specifies TCHAR

int main()
{
std::string test("Hello"); // string to be converted

// first, if you need a const TCHAR *

std::basic_string<TCHAR> converted(test.begin(), test.end());

const TCHAR *tchar = converted.c_str();

// use tchar as it is in the required form (const)

// second, if you need a TCHAR * (not const)

std::vector<TCHAR> converted2(test.begin(), test.end());

TCHAR *tchar2 = &converted2[0];

// use tchar2 as it is of the required form (non-const).

}

std::basic_string does not provide a means in all C++ standards to obtain a non-const pointer to its data, but std::vector does. (Assuming you don't use an explicit conversion to introduce or remove constness).

In C++17 and later, things are simpler: the basic_string::data() has both a const and non-const overload, which wasn't the case before the 2017 standard. Before C++11, the data in a basic_string was not guaranteed to be contiguous by the standard (even if implementations typically implemented things that way) but c_str() did provide the address of the first character of a contiguous array. The net effect is that, in C++17 and later, appropriate overloads of basic_string::data() or basic_string::c_str() can be used, without a need for cast to change constness, and without resorting to a vector (which has been guaranteed to have contiguous elements in all C++ standards).

Points to note in both cases

  1. The pointers (tchar and tchar2) are invalidated if their respective containers (converted or converted2) are resized or if they cease to exist. For example, don't use the data pointed to by tchar if converted has passed out of scope, since data tchar points at will no longer exist.
  2. It is simply undefined behaviour to use the pointers to run past the end (no magical resizing when using the pointers).

C++ TCHAR array to wstring not working in VS2010

There are functions like

mbstowcs_s()

that convert from char* to wchar_t*.

#include <iostream>
#include <stdlib.h>
#include <string>

using namespace std;

char *orig = "Hello, World!";
cout << orig << " (char *)" << endl;

// Convert to a wchar_t*
size_t origsize = strlen(orig) + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
wchar_t wcstring[newsize];
mbstowcs_s(&convertedChars, wcstring, origsize, orig, _TRUNCATE);
wcscat_s(wcstring, L" (wchar_t *)");
wcout << wcstring << endl;

Look here for an article and here for MSDN.



Related Topics



Leave a reply



Submit