tags:

views:

33

answers:

2

I have the following piece of code in C++:

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main(){
    wstring ws1 = L"Infinity: \u2210";
    wstring ws2 = L"Euro: €";

    wchar_t w[] = L"Sterling Pound: £";

    wfstream out("/tmp/unicode.txt");
    out.write(ws1.c_str(), ws1.size());
    out << ws1 << endl << ws2 << endl << w << endl;
    out.flush();
    out.close();
}

The program compiles without problem but the file is never open let alone writen on. Moreover, if I use std::wcout I still don't get the right output, just ? for the infinity and pound symbols.

My system is g++ 4.4.3 running an ubuntu linux 10.4 64bits.

+1  A: 

Always set the locale first… do locale::global( locale( "" ) );. Before that, you're in plain C mode which knows nothing about UTF-8.

On Darwin, this is broken, so I need to do setlocale( LC_ALL, "" );, but then your program works for me.

Edit

Oops, you got bit by two gotchas at once. Opening a wfstream with the default openmode does not create the file. I inadvertently fixed this to wofstream before running your program, and then forgot I did. Sorry. So:

wofstream out("/tmp/unicode.txt");

or

wfstream out("/tmp/unicode.txt", ios::in | ios::out | ios::trunc );
Potatoswatter
+1  A: 

There is not a definion in the standard on how wide character stream is converted to a a character device and you need to experiment with your system to find out what is happening. Usually setting the local via C should work for the std in/out streams std::cin/std::cout.

setlocale("");  // Loads the local that the machine is configured for (see you config)
                // If it is not configured it default to the "C" locale

File stream objects may not automatically retrieve the local, so sometimes it is worth explicitly setting the local of the stream.

std::locale   defaultLocale(""); // from machine config
std::wfstream out;
out.imbue(defaultLocale);        // imbue must be done before opening
                                 // otherwise it is ignored.

out.open("/tmp/unicode.txt");

Lets do some tests to make sure you are actually writing:

if (!out)
{
    std::cout << "Failed to open file\n";
}

As a side note:

out.write(ws1.c_str(), ws1.size()); // size() is the number of characters (wide)
                                    // write is expecting the number of bytes.

Another Note:

out.flush();    // flush() happens automatically when the file is closed
out.close();    // close() happens automatically when the stream is destroyed.
                // So technically it is better not to use these
                // as they are specific to file streams which will prevent you from
                // easily replacing this with a generic stream
Martin York
Unfair not to give you the right answer, both were right but I had decided to check the other almost twenty minutes before. Next time
Sambatyon