HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Converting from std::wstring to std::string in Linux

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
stdwstringlinuxconvertingfromstring

Problem

I was bothered by inability of C++ to mix cout and wcout in the same program - so I've found this question:

Converting between std::wstring and std::string

It didn't help me because it was mostly about MS Windows (I'm on Linux), but thanks to it I've found something similar to the WideCharToMultiByte functions in the C++ standard library.

My goal was just to output wide strings to cout intermittently with regular strings. I've written two variants of conversion function, which take wide string as an argument and return a regular string, containing multi-byte characters, ready to be sent to the cout (provided that the locale is appropriate).

#include 
#include 

using std::cout;
using std::endl;

struct T
{
  std::string a;
  std::wstring b;
};

std::string Convert1(const std::wstring& WS)
// ------ conversion using the wcstombs function 
{
  const unsigned wlen = WS.length();
  char buf[wlen * sizeof(std::wstring::value_type) + 1];
  const ssize_t res = std::wcstombs(buf, WS.c_str(), sizeof(buf));
  return (res >= 0) ? buf : "?";
}

std::string Convert2(const std::wstring& WS)
// ------ conversion using the wcsrtombs function 
{
  mbstate_t st = {};
  const unsigned wlen = WS.length();
  wchar_t wbuf[wlen + 1];
  const size_t copied = WS.copy(wbuf, wlen);
  wbuf[copied] = L'\0';
  const wchar_t* wptr = wbuf;
  char buf[wlen * sizeof(std::wstring::value_type) + 1];
  const ssize_t res = std::wcsrtombs(buf, &wptr, sizeof(buf), &st);
  return (res >= 0) ? buf : "?";
}

int main()
{
  T t = {"Hello", L"Привет"};
  std::setlocale(LC_ALL, "en_US.utf8");
  cout << t.a << endl;
  cout << Convert2(t.b) << endl;
}


It works for me now... Will it work in other setups?

Solution

-
ssize_t is essentially unsigned; that is, the comparison res >= 0 is always true.

The test should be

res != static_cast(-1)


-
` and headers are missing

-
You don't need to
WS.copy(wbuf, wlen).

In fact, you don't need
wbuf at all:

const wchar_t * wptr = WS.c_str();
std::wcsrtombs(buf, &wptr, sizeof(buf), &st);


works just fine.

-
I am not sure that calculating buffer length via
sizeof(std::wstring::value_type) is a right way. How can you be sure that multibyte sequence will fit? I'd recommend to obtain required size by passing NULL to wcsrtombs`.

PS: И тебе привет

Code Snippets

res != static_cast<std::size_t>(-1)
const wchar_t * wptr = WS.c_str();
std::wcsrtombs(buf, &wptr, sizeof(buf), &st);

Context

StackExchange Code Review Q#54000, answer score: 4

Revisions (0)

No revisions yet.