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
= alwayschar*
LPWSTR
= alwayswchar_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 const
ness).
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 const
ness, and without resorting to a vector
(which has been guaranteed to have contiguous elements in all C++ standards).
Points to note in both cases
- The pointers (
tchar
andtchar2
) are invalidated if their respective containers (converted
orconverted2
) are resized or if they cease to exist. For example, don't use the data pointed to bytchar
ifconverted
has passed out of scope, since datatchar
points at will no longer exist. - 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
Execute Rdmsr and Wrmsr Instructions from C/C++ Code
Fseek Does Not Work When File Is Opened in "A" (Append) Mode
Can This MACro Be Converted to a Function
Linux Serial Port Reading - How to Change Size of Input Buffer
Gcc 7, -Wimplicit-Fallthrough Warnings, and Portable Way to Clear Them
Copy Constructor of Derived Qt Class
Volatile Struct = Struct Not Possible, Why
In C/C++, Are Volatile Variables Guaranteed to Have Eventually Consistent Semantics Betwen Threads
How to Find How Much Memory Is Shared Between Forked Process with Copy-On-Write in Linux
Popen() Writes Output of Command Executed to Cout
Windows Named Pipe Support in Linux
Gcc Does Not Honor 'Pragma Gcc Diagnostic' to Silence Warnings
C++11 Struct Initialization Compilation Error
Could Not Load Spatialite Extension in Qsqlite ( Qt 5.9)
Error: Declaration Does Not Declare Anything
In C++, Is There a Difference Between "Throw" and "Throw Ex"