mbstowcs, wcstombs

http://d.hatena.ne.jp/janus_wel/20100315/1268654296 の C 標準関数版。

// nwconv_c.hpp

#ifndef NWCONV_C_HPP
#define NWCONV_C_HPP

#include <string>
#include <vector>
#include <cstdlib>
#include "../../header/wexcept.hpp"

#ifdef _MSC_VER
#   include <errno.h>
#endif

namespace util {
    namespace string {
        std::wstring ntow(const std::string& src) {
#ifdef _MSC_VER
            const std::size_t src_size = src.length() + 1;
            const std::size_t dst_size = src_size;
            std::size_t converted;
            std::vector<wchar_t> dst_vctr(dst_size + 1);
            wchar_t* dst = &dst_vctr[0];
            if (mbstowcs_s(&converted, dst, dst_size, src.c_str(), _TRUNCATE) != EINVAL) {
                return std::wstring(dst);
            }
#else
            const std::size_t size = std::mbstowcs(NULL, src.c_str(), 0);
            std::vector<wchar_t> dst_vctr(size + 1);
            wchar_t* dst = &dst_vctr[0];

            if (std::mbstowcs(dst, src.c_str(), size) == size) {
                return std::wstring(dst);
            }
#endif

            std::string errmsg("failed: ");
            errmsg.append(src);
            throw std::logic_error(errmsg);
        }

        std::string wton(const std::wstring& src) {
#ifdef _MSC_VER
            const std::size_t src_size = src.length() + 1;
            const std::size_t dst_size = src_size * MB_CUR_MAX;
            std::size_t converted;
            std::vector<char> dst_vctr(dst_size + 1);
            char* dst = &dst_vctr[0];
            if (wcstombs_s(&converted, dst, dst_size, src.c_str(), _TRUNCATE) != EINVAL) {
                return std::string(dst);
            }
#else
            std::size_t size = std::wcstombs(NULL, src.c_str(), 0);
            std::vector<char> dst_vctr(size + 1);
            char* dst = &dst_vctr[0];

            if (std::wcstombs(dst, src.c_str(), size) == size) {
                return std::string(dst);
            }
#endif

            std::wstring errmsg(L"failed: ");
            errmsg.append(src);
            throw util::exception::wlogic_error(errmsg);
        }

    }
}

#endif // NWCONV_C_HPP

と定義しておいて以下のように使う。同様に command line で指定された文字列の最初の一文字を落として表示する例。

// main.cpp

#include <string>
#include <locale>
#include <iostream>
#include <stdexcept>
#include "wexcept.hpp"
#include "nwconv_c.hpp"

void initialize_locale(void);

int main(const int argc, const char* const argv[]) {
    initialize_locale();

    try {
        for (int i = 0; i < argc; ++i) {
            std::wstring arg = util::string::ntow(argv[i]);
            arg.erase(0, 1);
            std::cout << util::string::wton(arg) << std::endl;
        }
    }
    catch (const std::exception& ex) {
        std::cerr << ex.what() << std::endl;
    }
    catch (const util::exception::wexception& ex) {
        std::wcerr << ex.what() << std::endl;
    }

    return 0;
}

void initialize_locale(void) {
    std::locale system_locale("");
    std::locale::global(system_locale);
    std::cin.imbue(system_locale);
    std::cout.imbue(system_locale);
    std::cerr.imbue(system_locale);
    std::wcin.imbue(system_locale);
    std::wcout.imbue(system_locale);
    std::wcerr.imbue(system_locale);
}

こっちは global locale に system locale を設定してやらないといけない。上記の initialize_locale() 関数のようについでに既存の stream object に対して imbue をしておくと何かと都合がいいかも。

こっちも VC++ 2008 Express Edition と andLinux g++ 4.3.3 で動作確認してる。あとこっちだと VC++ & cmd.exe で wton で変換 & cout で出力という手順を踏まなくても wcout を使ってそのまま出力できる。 VC++ の locale の取り扱いがおかしいのかな。