StringCchCat for concatenating integers with strings in VC++ - c++

I want to concatenate integer with string like this:
My code snippet is like this.
TCHAR dest[MAX_PATH];
int i = 2;
StringCchCopy(dest,MAX_PATH,"Begining_");
StringCchCat(dest,MAX_PATH,LPCTSTR(i));
The last line is causing an exception. I know the last line is wrong.
"Begining" & the concatenated string should be "Begining_2". How do I achieve this in C++ ?

The quick fix for your code:
TCHAR dest[MAX_PATH];
int i = 2;
_stprintf_s(dest, MAX_PATH, _T("Begining_%d"), i);
As you can see I've simplified it and made it more secure. So there is no need to use StringCchCopy/StringCchCat functions.
Please note that the way you doing it is pure C, in C++ on Windows platform it should be done like this:
Using MFC framework (UNICODE compliant):
int i = 2;
CString sDest;
sDest.Format(_T("Begining_%d"), i);
The CString does have (LPCTSTR) cast operator. So you can use it directly in any function that accepts LPCTSTR type of parameter.
standard C++ way (UNICODE compliant):
int i = 2;
std::wstring dest(L"Begining_");
dest += std::to_wstring(i);
LPCWSTR str = dest.c_str();

Try this code
int i = 2;
std::wstring ext = std::to_wstring(i); // convert integer to wstring
StringCchCat(dest, MAX_PATH, ext.c_str()); // pass wstring here

Related

Concatenating strings of different types in C++

How can I concatenate the following char and TCHAR variables in C++?
TCHAR fileName[50];
TCHAR prefix[5] = "file_";
TCHAR ext[4] = ".csv";
char *id[10];
generateId(*id);
The generateId(char *s) function simply generates a random string.
I need to end up with fileName being something like file_randomIdGoesHere.csv
I have tried strncat(fileName, prefix, 5); which works fine with all TCHAR variables but not with char * as it requires a const char * instead, so maybe there's a better way of doing it, not sure how to convert char * or char ** to const char *.
Any ideas?
The error I get with strncat(fileName, id, 10) is error: cannot convert 'char**' to 'const char*'
The error you are seeing is because your id array is declared wrong. You declared an array of pointers instead of an array of characters. It should be more like this:
char id[10];
generateId(id);
That being said, you are also assigning char-based string literals to your TCHAR arrays, which means you are not compiling your project for Unicode, otherwise such assignments would fail to compile. So you may as well replace TCHAR with char:
char fileName[50] = {0};
char prefix[] = "file_";
char ext[] = ".csv";
char id[10] = {0};
generateId(id);
And then, you should change strncat() to _snprintf():
_snprintf(filename, 49, "%s%s.cvs", prefix, id);
If you really want to use TCHAR then you need to change everything to TCHAR, and use the TEXT() macro for literals:
TCHAR fileName[50] = {0};
TCHAR prefix[] = TEXT("file_");
TCHAR ext[] = TEXT(".csv");
TCHAR id[10] = {0};
generateId(id);
__sntprintf(filename, 49, TEXT("%s%s.cvs"), prefix, id);
If you cannot change id to TCHAR then you will have to perform a runtime conversion:
TCHAR fileName[50] = {0};
TCHAR prefix[] = TEXT("file_");
TCHAR ext[] = TEXT(".csv");
char id[10] = {0};
generateId(id);
#ifdef UNICODE
wchar_t id2[10] = {0};
MultiByteToWideChar(CP_ACP, 0, id, -1, id2, 10);
#else
char *id2 = id;
#endif
__sntprintf(filename, 49, TEXT("%s%s.cvs"), prefix, id2);
The first thing you should do is, since you are using C++ and not pure C, just use a string class to represent your strings and to manage them in a way much more convenient than raw C-style character arrays.
In the context of Windows C++ programming, CString is a very convenient string class.
You can use its overloaded operator+ (or +=) to concatenate strings in a convenient, robust and easy way.
If you have an id stored in a char string (as an ASCII string), as you showed in your question's code:
char id[10];
generateId(id);
you can first create a CString around it (this will also convert from char-string to TCHAR-string, in particular to wchar_t-string if you are using Unicode builds, which have been the default since VS2005):
const CString strId(id);
Then, you can build the whole file name string:
//
// Build file name using this format:
//
// file_<generatedIdGoesHere>.csv
//
CString filename(_T("file_"));
filename += strId;
filename += _T(".csv");
As an alternative, you could also use the CString::Format method, e.g.:
CString filename;
filename.Format(_T("file_%s.csv"), strId.GetString());
You can simply pass instances of CString to LPCTSTR parameters in Win32 APIs, since CString offers an implicit conversion to LPCTSTR (i.e. const TCHAR*).
To use CString, you can simply #include <atlstr.h>.
First, convert char to TCHAR (see How to convert char* to TCHAR[ ]? )
Then, concatenate two TCHAR strings using _tcscat().
If you are not using UNICODE character table. Than your TCHAR is equivalent to char.
TCHAR prefix[6] = "file_"; //don't forget to allocate space for null terminator '\0'
TCHAR ext[5] = ".csv"; // size is not 4, remember null terminator
char id[10] = "random"; // no need to use char* here
std::ostringstream oss;
oss << prefix << id << ext << std::endl;
std::cout << oss.str() << std::endl; // gives you file_random.csv as output

Converting string to LPCTSTR

I encountered a problem during writting my code. I use a function which take as an argument object which type is LPCSTR. The object declaration looks like shown below:
LPCTSTR lpFileName;
Firstly, I used defined variable, which was futher assign to lpFileName like this:
#define COM_NR L"COM3"
lpFileName = COM_NR
Using this manner, I could easily pass lpFileName argument to the function. Anyway, i had to changed the way of defining my port number. Currently i read text from *.txt file and save it as string variable e.g "COM3" or "COM10". The main problem is to convert string to LPCSTR properly. I found good solution but finally it doesn't seem working properly. My code looks like this:
string temp;
\\code that fill temp\\
wstring ws;
ws.assign(temp.begin(),temp.end());
I thought that conversion went correctly, maybe it did and I don't get it because when i print few things it makes me to wonder why it doesn't work as i want:
cout temp_cstr(): COM3
cout LCOM3: 0x40e586
cout ws.c_str(): 0x8b49b2c
Why LCOM3 and ws.c_str() doesn't contain the same? When i pass lpFileName = ws.c_str() to my function, it works uncorretly. On the other hand, passing lpFileName = L"COM3" gives success.
I code using cpp, and IDE is QtCreator
Eventually, I managed with the pitfall using conversion-function s2ws() and doing few operations. I place my soultion here for people who will have similar troubles with converting string. In my first post i wrote that i needed to convert string to LPCTSTR and finally it turned out that argument in my function is not, LPCTSTR but LPCWSTR that is const wchar_t*.
So, soulution:
string = "COM3";
wstring stemp;
LPCWSTR result_port;
stemp = s2ws(port_nr);
result_port = stemp.c_str(); // now passing result_port to my function i am getting success
declaration of s2ws:
wstring s2ws(const std::string& s)
{
int len;
int slength = (int)s.length() + 1;
len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
wchar_t* buf = new wchar_t[len];
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
std::wstring r(buf);
delete[] buf;
return r;
}
Try to use wostringstream:
string temp;
\\code that fill temp\\
wostringstream ost;
ost << temp.c_str();
wstring ws = ost.str();
I have struggled with this for quite a while. After quite a bit of digging I found this works the best; you could try this.
std::string t = "xyz";
CA2T wt (t.c_str());

C++ WCHAR manipulations

I'm developing a tiny Win32 app in C++.
I've studied C++ fundamentals long time ago, so now I completely confused because of character strings in C++. There were no WCHAR or TCHAR only char and String.
After a little investigation I've decided not to use TCHAR.
My issue is very simple I think, but I can't find clear guide how to manipulate strings in C++. Affected by PHP coding last few years I've expected something simple with strings manipulations and was wrong!
Simply, all I need is to put new data to a character string.
WCHAR* cs = L"\0";
swprintf( cs, "NEW DATA" );
This was my first attempt. When debugging my app I've investigated that swprintf puts only first 2 chars to my cs var. I've resolved my problem this way:
WCHAR cs[1000];
swprintf( cs, "NEW DATA" );
But generally this trick could fail, because in my case new data is not constant value but another variable, that could potentialy be wider, than 1000 chars long. And my code is looks like this:
WCHAR cs[1000];
WCHAR* nd1;
WCHAR* nd2;
wcscpy(nd1, L"Some value");
wcscpy(nd2, L"Another value"); // Actually these vars stores the path for user selected folder
swprintf( cs, "The paths are %s and %s", nd1, nd2);
In this case there is possibility than nd1 and nd2 total character count could be greater than 1000 chars so critical data will be lost.
The question is how can I copy all data I need to WCHAR string declared this way WCHAR* wchar_var; without losing anything?
P.S. Since I'm Russian the question may be unclear. Let me now about that, and I'll try to explain my issue more clear and complex.
In modern Windows programming, it's OK to just ignore TCHAR and instead use wchar_t (WCHAR) and Unicode UTF-16.
(TCHAR is a model of the past, when you wanted to have a single code base, and produce both ANSI/MBCS and Unicode builds changing some preprocessor switches like _UNICODE and UNICODE.)
In any case, you should use C++ and convenient string classes to simplify your code. You can use ATL::CString (which corresponds to CStringW in Unicode builds, which are the default since VS2005), or STL's std::wstring.
Using CString, you can do:
CString str1 = L"Some value";
CString str2 = L"Another value";
CString cs;
cs.Format(L"The paths are %s and %s", str1.GetString(), str2.GetString());
CString also provides proper overloads of operator+ to concatenate strings (so you don't have to calculate the total length of the resulting string, dynamically allocate a buffer for the destination string or check existing buffer size, call wcscpy, wcscat, don't forget to release the buffer, etc.)
And you can simply pass instances of CString to Win32 APIs expecting const wchar_t* (LPCWSTR/PCWSTR) parameters, since CString offers an implicit conversion operator to const wchar_t*.
When you're using a WCHAR*, you are invoking undefined behavior because you have a pointer but have not made it point to anything valid. You need to find out how long the resulting string will be and dynamically allocate space for the string. For example:
WCHAR* cs;
WCHAR* nd1;
WCHAR* nd2;
nd1 = new WCHAR[lstrlen(L"Some value") + 1]; // +1 for the null terminator
nd2 = new WCHAR[lstrlen(L"Another value") + 1];
cs = new WCHAR[lstrlen(L"The paths are and ") + lstrlen(nd1) + lstrlen(nd2) + 1];
wcscpy(nd1, L"Some value");
wcscpy(nd2, L"Another value"); // Actually these vars stores the path for user selected folder
swprintf( cs, L"The paths are %s and %s", nd1, nd2);
delete[] nd1;
delete[] nd2;
delete[] cs;
But this is very ugly and error-prone. As noted, you should be using std::wstring instead, something like this:
std::wstring cs;
std::wstring nd1;
std::wstring nd2;
nd1 = L"Some value";
nd2 = L"Another value";
cs = std::wstring(L"The paths are ") + nd1 + L" and " + nd2;
Suggest to use ATL CStringW class instead of raw WCHAR, it's much more handy. CString is wrapper for dynamically allocated C-string. It will manage string length & allocated memory buffer appropriately after each operation so you wouldn't care on it.
Typical usage:
#include <atlstr.h>
CStringW s;
s.Format(L"The paths are %s and %s", L"Some value", L"Another value");
const WCHAR* wstr = s.GetString(); // To pass to some API that need WCHAR
or
#include <atlstr.h>
CStringW s(L"The paths are ");
s += L"Some value";
s += L" and ";
s += L"Another value";
const WCHAR* wstr = s.GetString(); // To pass to some API that need WCHAR

How to get codepoint of particular WCHAR character?

For example I need codepoint of 5th character here, that is ð
const WCHAR* mystring = L"Þátíð";
I know that it has code point : U+00F0 - but how to get this integer using c++ ?
WCHAR in Windows 2000 and later is UTF-16LE so it is not necessarily safe to access a specific character in a string by index. You should use something like CharNext to walk the string to get correct handling of surrogate pairs and combining characters/diacritics.
In this specific example Forgottn's answer depends on the compiler emitting precomposed versions of the á and í characters... (This is probably true for most Windows compilers, porting to Mac OS is probably problematic)
const WCHAR myString[] = L"Þátíð";
size_t myStringLength = 0;
if(SUCCEEDED(StringCchLengthW(myString, STRSAFE_MAX_CCH, &myStringLength))
{
LPCWSTR myStringIterator = myString;
for(size_t sz = 0; sz < myStringLength; ++sz)
{
unsigned int mySuperSecretUnicodeCharacter = *myStringIterator;
LPCWSTR myNextIterator = CharNext(myStringIterator);
std::vector<unsigned int> diacriticsOfMySuperSecretUnicodeCharacter(myStringIterator+1, myNextIterator);
myStringIterator = myNextIterator;
}
}
Edit 1: made it actually work
Edit 2: made it actually look for all codepoints

Convert CString to string (VC6)

I want to convert CString to string. (Yup. I know what am I doing. I know the returned string will be incorrect, if CString value range is outside ANSI, but That's Is OK!)
The following code will work under VC2008.
std::string Utils::CString2String(const CString& cString)
{
// Convert a TCHAR string to a LPCSTR
CT2CA pszConvertedAnsiString (cString);
// construct a std::string using the LPCSTR input
std::string strStd (pszConvertedAnsiString);
return strStd;
}
But VC6 doesn't have CT2CA macro. How I can make the code to work as well in both VC6 and VC2008?
Microsoft says that CT2CA replaces T2CA, so try the latter and see if that works.
Since you don't care about characters outside the ANSI range, brute force would work.
std::string Utils::CString2String(const CString& cString)
{
std::string strStd;
for (int i = 0; i < cString.GetLength(); ++i)
{
if (cString[i] <= 0x7f)
strStd.append(1, static_cast<char>(cString[i]));
else
strStd.append(1, '?');
}
return strStd;
}