wcstombs & wchar_t issues

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Post Reply
LexRutter
Posts: 4
Joined: Sat Dec 05, 2020 9:52 am

wcstombs & wchar_t issues

Post by LexRutter »

Using C++Builder 10.4 (latest updates as of 5-Dec-2020) and attempting to use some sample code from RAD Studio Docwiki (specifically the C++ Version & not Delphi) [Environment & target: Windows 10, 32 bit target] I've run into a couple issues. The example code simply breaks.

Issue 1: wcstombs, which is documented to convert wchar_t string to char string: Apparently this converts only the very first item in the string. the result shows only the first character, and looking @ a watch on the wchar_t and the char variables, it shows a full string in wchar_t, just a single character in the char string.

Issue2: attempting to use this code (directly from the example, with the headers as noted in the example)
wchar_t *pwcsEOL = L'\0';
char *pwchi= L"Hi there!";

results in error messages saying that cannot initialize wchar_t to an rvalue of wchar_t; the char is the same. Since these are the explicit examples as posted int eh code in the Docwiki, I'm not sure what to do.

Any help, especially with converting w wchar_t (character in an array, or as an entire string) would be appreciated.

Below is the code, directly from Docwiki. I'm only trying to use the single line: x = wcstombs( pbuf, pwchi,MB_CUR_MAX);, but have attempted to set it up with the entire 4 variable definition & initialization lines. The last 2 give errors. Using a previously generated
wchar_t TestVar *; line & filling it from System Time is accepted by wcstombs, but yields only 1 character converted.

Example

#include <stdio.h>
#include <stdlib.h>
void main(void)
{
int x;
char *pbuf = (char*)malloc( MB_CUR_MAX);
wchar_t *pwcsEOL = L'\0';
char *pwchi= L"Hi there!";

printf (" Convert entire wchar string into a multibyte string:\n");
x = wcstombs( pbuf, pwchi,MB_CUR_MAX);
printf ("Character converted: %u\n", x);
printf ("Multibyte string character: %1s\n\n",pbuf);
printf (" Convert when target is NULL\n");
x = wcstombs( pbuf, pwcsEOL, MB_CUR_MAX);
printf ("Character converted: %u\n",x);
printf ("Multibyte string: %1s\n\n",pbuf);

}
rlebeau
BCBJ Author
BCBJ Author
Posts: 1759
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: wcstombs & wchar_t issues

Post by rlebeau »

LexRutter wrote: Sat Dec 05, 2020 10:24 am Using C++Builder 10.4 (latest updates as of 5-Dec-2020) and attempting to use some sample code from RAD Studio Docwiki (specifically the C++ Version & not Delphi) [Environment & target: Windows 10, 32 bit target] I've run into a couple issues. The example code simply breaks.
The DocWiki example you are looking at has many mistakes in it, so it is no wonder why you are having trouble with it.
LexRutter wrote: Sat Dec 05, 2020 10:24 am Issue 1: wcstombs, which is documented to convert wchar_t string to char string: Apparently this converts only the very first item in the string. the result shows only the first character, and looking @ a watch on the wchar_t and the char variables, it shows a full string in wchar_t, just a single character in the char string.
That is because MB_CUR_MAX "defines an integer expression giving the maximum number of bytes needed to represent a single wide character in the current locale", which in your case is likely 1 byte. So the pbuf buffer is not large enough to hold more than 1 char on output. You can verify that by looking at the return value of wcstombs(), which returns the number of chars output, not counting a null terminator.
LexRutter wrote: Sat Dec 05, 2020 10:24 am Issue2: attempting to use this code (directly from the example, with the headers as noted in the example)
wchar_t *pwcsEOL = L'\0';
char *pwchi= L"Hi there!";

results in error messages saying that cannot initialize wchar_t to an rvalue of wchar_t; the char is the same.
That code is completely wrong. It is trying to assign a single wchar_t to a wchar_t* pointer, and it is trying to assign a const wchar_t[] string literal to a char* pointer. Both of which are wrong and will not compile.

The pwcsEOL mistake can be fixed by doing either this:

Code: Select all

wchar_t wcsEOL = L'\0';
...
x = wcstombs( pbuf, &wcsEOL, MB_CUR_MAX);
Or this:

Code: Select all

const wchar_t *wcsEOL = L"\0";
...
x = wcstombs( pbuf, pwcsEOL, MB_CUR_MAX);
The pwchi mistake can be fixed by changing it to a const wchar_t* pointer:

Code: Select all

const wchar_t *pwchi = L"Hi there!";
LexRutter wrote: Sat Dec 05, 2020 10:24 am Below is the code, directly from Docwiki.
Try this instead:

Code: Select all

#include <stdio.h> // better: <cstdio>
#include <stdlib.h> // better: <cstdlib>

/* uncomment this if using the <c...> C++ headers above...
using std::printf;
using std::wcstombs;
*/

int main()
{
	size_t x;
	char buf[20];
	const wchar_t *pwcsEOL = L"\0";
	const char *pwchi = L"Hi there!";

	printf ("Convert entire wchar string into a multibyte string:\n");
	x = wcstombs( buf, pwchi, 20 );
	printf ("Character converted: %zu\n", x);
	if (x != (size_t)-1) {
		printf ("Multibyte string character: %.*s\n\n", (int)x, buf);
	}
	printf ("Convert when target is NULL\n");
	x = wcstombs( buf, pwcsEOL, 20 );
	printf ("Character converted: %zu\n", x);
	if (x != (size_t)-1) {
		printf ("Multibyte string: %.*s\n\n", (int)x, buf);
	}

	return 0;
}
That being said, there is a much simply solution. If you are willing to use C++ instead of C, and use the Delphi-based RTL instead of the C runtime library (especially since you are using C++Builder, after all), then try this instead:

Code: Select all

#include <vcl.h>
#pragma hdrstop

#include <iostream>
using std::cout;

int main()
{
	AnsiString str;
	UnicodeString pwcsEOL = L"\0";
	UnicodeString pwchi = L"Hi there!";

	cout << "Convert entire wchar string into a multibyte string:\n";
	str = pwchi;
	cout << "Character converted: " << str.Length() << "\n";
	cout << "Multibyte string character: " << str.c_str() << "\n\n";
	cout << "Convert when target is NULL\n";
	str = pwcsEOL;
	cout << "Character converted: " << str.Length() << "\n";
	cout << "Multibyte string: " << str.c_str() << "\n\n";

	return 0;
}
Remy Lebeau (TeamB)
Lebeau Software
LexRutter
Posts: 4
Joined: Sat Dec 05, 2020 9:52 am

Re: wcstombs & wchar_t issues

Post by LexRutter »

Thanks very much, I do appreciate the detailed response, it's quite helpful.

Some additional comments, the code with the note "it's wrong" happens to come directly from the Embarcadero Help page examples. I really appreciated the note about it - gets a bit frustrating when the Examples and samples don't work.

I did eventually find some other, more elegant solutions to the problem. Along the way I also discovered that the example routine for converting a single character actually give a large destination and a single-character source. It would appear that the functions are actually written with some issues. (Even with a large-bite target, the way it's written you can only use a single-character source, where the function I tried to use lets you use any length source, but only allows a single character in the destination. I did notice that while working with it originally.)

Finally, I've been trying to work mostly with C++ and Builder VCL calls. Without any written libraries (i.e. Books), and what I'd term an awkward help & search function, it's been a struggle to find the best, most logical routines. This forum looks like it's a wealth of information. I'll close by repeating: Thanks for all the comments and pointers. Really a big help.
Post Reply