3

I'm new to C++ and I have this issue. I have a string called DATA_DIR that I need for format into a wstring.

string str = DATA_DIR;
std::wstring temp(L"%s",str); 

Visual Studio tells me that there is no instance of constructor that matches with the argument list. Clearly, I'm doing something wrong.

I found this example online

std::wstring someText( L"hello world!" );

which apparently works (no compile errors). My question is, how do I get the string value stored in DATA_DIR into the wstring constructor as opposed to something arbitrary like "hello world"?

user2619824
  • 478
  • 1
  • 5
  • 20
  • possible duplicate of [How to convert std::string to LPCWSTR in C++ (Unicode)](http://stackoverflow.com/questions/27220/how-to-convert-stdstring-to-lpcwstr-in-c-unicode) – Ani Aug 14 '13 at 23:58
  • Check out http://www.utf8everywhere.org/ and consider using the boost::nowide library provided on that page to convert string to wstring and back. Makes life much easier :) – Tom Aug 15 '13 at 00:21
  • 1
    What is the encoding of the text in the `string`? Usually either ISO/IEC 8859-1 (Which many incorrectly call "ASCII") or UTF-8. – Mooing Duck Aug 15 '13 at 00:28
  • Please see my edit below. My original code had a big mistake in it. – David G Aug 16 '13 at 00:58

6 Answers6

7

This is in reference to the most up-voted answer but I don't have enough "reputation" to just comment directly on the answer.

The name of the function in the solution "wstring_from_bytes" implies it is doing what the original poster wants, which is to get a wstring given a string, but the function is actually doing the opposite of what the original poster asked for and would more accurately be named "bytes_from_wstring".

To convert from string to wstring, the wstring_from_bytes function should use mbstowcs not wcstombs

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <cstdlib>
#include <string>

std::wstring wstring_from_bytes(std::string const& str)
{
    size_t requiredSize = 0;
    std::wstring answer;
    wchar_t *pWTempString = NULL;

    /*
    * Call the conversion function without the output buffer to get the required size
    *  - Add one to leave room for the NULL terminator
    */
    requiredSize = mbstowcs(NULL, str.c_str(), 0) + 1;

    /* Allocate the output string (Add one to leave room for the NULL terminator) */  
    pWTempString = (wchar_t *)malloc( requiredSize * sizeof( wchar_t ));  
    if (pWTempString == NULL)  
    {  
        printf("Memory allocation failure.\n");  
    }
    else
    {
        // Call the conversion function with the output buffer
        size_t size = mbstowcs( pWTempString, str.c_str(), requiredSize);
        if (size == (size_t) (-1))  
        {  
            printf("Couldn't convert string\n");  
        }
        else
        {
            answer = pWTempString;
        }
    }


    if (pWTempString != NULL)
    {
        delete[] pWTempString;
    }

    return answer;
}

int main()
{
   std::string str = "abcd";
   std::wstring wstr = wstring_from_bytes(str);
}

Regardless, this is much more easily done in newer versions of the standard library (C++ 11 and newer)

#include <locale>
#include <codecvt>
#include <string>

std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;

std::wstring wide = converter.from_bytes(narrow_utf8_source_string);
AJKepler
  • 71
  • 1
  • 2
6

Here is an implementation using wcstombs (Updated):

#include <iostream>
#include <cstdlib>
#include <string>
 
std::string wstring_from_bytes(std::wstring const& wstr)
{
    std::size_t size = sizeof(wstr.c_str());
    char *str = new char[size];
    std::string temp;
 
    std::wcstombs(str, wstr.c_str(), size);

    temp = str;
    delete[] str;
 
    return temp;
}
 
int main()
{
    std::wstring wstr = L"abcd";
    std::string str = wstring_from_bytes(wstr);
}

Here is a demo.

Community
  • 1
  • 1
David G
  • 94,763
  • 41
  • 167
  • 253
  • This is funny! First `sizeof()` does not give you the length of the string, you have `strlen` or `wcslen` for that. Second, you didn't check for `empty()`. Third, you converted the other way around. And last but not least, you leaked the `str ` pointer in your linked example. – CodeAngry Mar 29 '23 at 19:27
  • I was new to this stuff back then :) – David G Mar 30 '23 at 02:30
4

printf-style format specifiers are not part of the C++ library and cannot be used to construct a string.

If the string may only contain single-byte characters, then the range constructor is sufficient.

std::string narrower( "hello" );
std::wstring wider( narrower.begin(), narrower.end() );

The problem is that we usually use wstring when wide characters are applicable (hence the w), which are represented in std::string by multibyte sequences. Doing this will cause each byte of a multibyte sequence to translate to an sequence of incorrect wide characters.

Moreover, to convert a multibyte sequence requires knowing its encoding. This information is not encapsulated by std::string nor std::wstring. C++11 allows you to specify an encoding and translate using std::wstring_convert, but I'm not sure how widely supported it is of yet. See 0x....'s excellent answer.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
1

The converter mentioned for C++11 and above has deprecated this specific conversion in C++17, and suggests using the MultiByteToWideChar function.

The compiler error (c4996) mentions defining _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING.

Tim
  • 39
  • 4
  • 1
    How does this answer the question? I think this would be better as a comment under the relevant answer. – Major Jul 12 '21 at 14:15
0
wstring temp = L"";
for (auto c : DATA_DIR)
   temp.push_back(c);
Gustavo
  • 1
  • 2
-1

I found this function. Could not find any predefined method to do this.

std::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;
}

std::wstring stemp = s2ws(myString);
Shashwat Kumar
  • 5,159
  • 2
  • 30
  • 66
  • This is not using the standard library. It looks like Win32. – Potatoswatter Aug 14 '13 at 23:55
  • Yea, its not using standard library. Asker is using Visual Studio. It can be of help if he is using WINAPI. – Shashwat Kumar Aug 14 '13 at 23:57
  • And what exactly does `CP_ACP` do? It appears to specify the a system-defined, non-multibyte encoding. This API makes it very difficult to write portably. – Potatoswatter Aug 15 '13 at 00:00
  • CP_ACP is to define the codepage when MultiByteToWideChar performs the conversion. CP_ACP defines it to be ANSI codepage. – Shashwat Kumar Aug 15 '13 at 00:05
  • And "ANSI codepage" is an ill-defined concept that is likely not to be what he wants. – Potatoswatter Aug 15 '13 at 00:06
  • I just answered what I used and what worked for me. It asker finds its working then its fine, and if not then other answers are also there using standard libraries. – Shashwat Kumar Aug 15 '13 at 00:10
  • Very often, insufficient testing (e.g. using only one machine or similar machines) allows poorly internationalized code to ship because problems only show up for foreign encodings. These days UTF-8 is a better choice than ISO 8859. Generally speaking, ANSI stands for *American* National Standards Institute, and they have no motive or authority to make standards regarding *international* communication, besides which Microsoft often abuses their name in an attempt to present their proprietary solutions as the "business standard." See http://en.wikipedia.org/wiki/Code_page : CP_ACP is not ANSI. – Potatoswatter Aug 15 '13 at 00:18
  • Not usable out of the box, the answer needs better annotation/explanation. – Arka Mukherjee Sep 17 '21 at 17:24