Saya memiliki aplikasi windows dengan tipe string WCHAR*. Saya perlu mengonversi ini menjadi char* untuk diteruskan ke C API. Saya menggunakan fungsi MultiByteToWideChar dan WideCharToMultiByte untuk melakukan konversi.

Tetapi untuk beberapa alasan, konversi tidak tepat. Saya melihat banyak omong kosong dalam output. Kode berikut adalah versi modifikasi yang ditemukan di ini jawaban stackoverflow.

WCHAR* convert_to_wstring(const char* str)
{
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, str, (int)strlen(str), NULL, 0);
    WCHAR* wstrTo = (WCHAR*)malloc(size_needed);
    MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)strlen(str), wstrTo, size_needed);
    return wstrTo;
}

char* convert_from_wstring(const WCHAR* wstr)
{
    int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)wcslen(wstr), NULL, 0, NULL, NULL);
    char* strTo = (char*)malloc(size_needed);
    WideCharToMultiByte(CP_UTF8, 0, wstr, (int)wcslen(wstr), strTo, size_needed, NULL, NULL);
    return strTo;
}

int main()
{
    const WCHAR* wText = L"Wide string";
    const char* text = convert_from_wstring(wText);
    std::cout << text << "\n";
    std::cout << convert_to_wstring("Multibyte string") << "\n";
    return 0;
}
2
Navaneeth K N 14 Maret 2017, 21:24

2 jawaban

Jawaban Terbaik

Fungsi konversi Anda bermasalah.

Nilai kembalian MultiByteToWideChar() adalah jumlah karakter lebar, bukan jumlah byte seperti yang Anda perlakukan saat ini. Anda perlu mengalikan nilai dengan sizeof(WCHAR) saat memanggil malloc().

Anda juga tidak memperhitungkan bahwa nilai kembalian TIDAK menyertakan spasi untuk terminator nol, karena Anda tidak meneruskan -1 dalam parameter cbMultiByte. Baca dokumentasi MultiByteToWideChar():

cbMultiByte [dalam]
Ukuran, dalam byte, dari string yang ditunjukkan oleh parameter lpMultiByteStr. Atau, parameter ini dapat diatur ke -1 jika string diakhiri dengan null. Perhatikan bahwa, jika cbMultiByte adalah 0, fungsi gagal.

Jika parameter ini adalah -1, fungsi memproses seluruh string input, termasuk karakter null terminasi. Oleh karena itu, string Unicode yang dihasilkan memiliki karakter null terminasi, dan panjang yang dikembalikan oleh fungsi menyertakan karakter ini.

Jika parameter ini disetel ke bilangan bulat positif, fungsi memproses dengan tepat jumlah byte yang ditentukan. Jika ukuran yang diberikan tidak menyertakan karakter null penghentian, string Unicode yang dihasilkan tidak diakhiri null, dan panjang yang dikembalikan tidak menyertakan karakter ini.

...

Nilai kembali

Mengembalikan jumlah karakter yang ditulis ke buffer yang ditunjukkan oleh lpWideCharStr jika berhasil. Jika fungsi berhasil dan cchWideChar adalah 0, nilai yang dikembalikan adalah ukuran yang diperlukan, dalam karakter, untuk buffer yang ditunjukkan oleh lpWideCharStr.

Anda tidak null-menghentikan string output Anda.

Hal yang sama berlaku dengan fungsi convert_from_wstring() Anda. Baca dokumentasi WideCharToMultiByte():

cchWideChar [dalam]
Ukuran, dalam karakter, dari string yang ditunjukkan oleh lpWideCharStr. Atau, parameter ini dapat diatur ke -1 jika string diakhiri dengan null. Jika cchWideChar disetel ke 0, fungsi gagal.

Jika parameter ini adalah -1, fungsi memproses seluruh string input, termasuk karakter null terminasi. Oleh karena itu, string karakter yang dihasilkan memiliki karakter null terminasi, dan panjang yang dikembalikan oleh fungsi menyertakan karakter ini.

Jika parameter ini disetel ke bilangan bulat positif, fungsi memproses dengan tepat jumlah karakter yang ditentukan. Jika ukuran yang diberikan tidak menyertakan karakter null penghentian, string karakter yang dihasilkan tidak diakhiri null, dan panjang yang dikembalikan tidak menyertakan karakter ini.

...

Nilai kembali

Mengembalikan jumlah byte yang ditulis ke buffer yang ditunjuk oleh lpMultiByteStr jika berhasil. Jika fungsi berhasil dan cbMultiByte adalah 0, nilai yang dikembalikan adalah ukuran yang diperlukan, dalam byte, untuk buffer yang ditunjukkan oleh lpMultiByteStr.

Karena itu, kode main() Anda membocorkan string yang dialokasikan. Karena mereka dialokasikan dengan malloc(), Anda perlu membatalkan alokasinya dengan free() setelah Anda selesai menggunakannya:

Selain itu, Anda tidak dapat meneruskan string WCHAR* ke std::cout. Ya, Anda bisa, tetapi tidak memiliki operator<< untuk input string lebar, tetapi memiliki input operator<< untuk void*, sehingga hanya akan menghasilkan keluaran alamat memori yang ditunjuk oleh WCHAR*, bukan karakter sebenarnya. Jika Anda ingin menampilkan string lebar, gunakan std::wcout sebagai gantinya.

Coba sesuatu yang lebih seperti ini:

WCHAR* convert_to_wstring(const char* str)
{
    int str_len = (int) strlen(str);
    int num_chars = MultiByteToWideChar(CP_UTF8, 0, str, str_len, NULL, 0);
    WCHAR* wstrTo = (WCHAR*) malloc((num_chars + 1) * sizeof(WCHAR));
    if (wstrTo)
    {
        MultiByteToWideChar(CP_UTF8, 0, str, str_len, wstrTo, num_chars);
        wstrTo[num_chars] = L'\0';
    }
    return wstrTo;
}

CHAR* convert_from_wstring(const WCHAR* wstr)
{
    int wstr_len = (int) wcslen(wstr);
    int num_chars = WideCharToMultiByte(CP_UTF8, 0, wstr, wstr_len, NULL, 0, NULL, NULL);
    CHAR* strTo = (CHAR*) malloc((num_chars + 1) * sizeof(CHAR));
    if (strTo)
    {
        WideCharToMultiByte(CP_UTF8, 0, wstr, wstr_len, strTo, num_chars, NULL, NULL);
        strTo[num_chars] = '\0';
    }
    return strTo;
}

int main()
{
    const WCHAR* wText = L"Wide string";
    const char* text = convert_from_wstring(wText);
    std::cout << text << "\n";
    free(text);

    const WCHAR *wtext = convert_to_wstring("Multibyte string");
    std::wcout << wtext << "\n";
    free(wtext);

    return 0;
}

Karena itu, Anda benar-benar harus menggunakan std::string dan std::wstring daripada char* dan wchar_t* untuk manajemen memori yang lebih baik:

std::wstring convert_to_wstring(const std::string &str)
{
    int num_chars = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0);
    std::wstring wstrTo;
    if (num_chars)
    {
        wstrTo.resize(num_chars);
        MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), &wstrTo[0], num_chars);
    }
    return wstrTo;
}

std::string convert_from_wstring(const std::wstring &wstr)
{
    int num_chars = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.length(), NULL, 0, NULL, NULL);
    std::string strTo;
    if (num_chars > 0)
    {
        strTo.resize(num_chars);
        WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.length(), &strTo[0], num_chars, NULL, NULL);
    }
    return strTo;
}

int main()
{
    const WCHAR* wText = L"Wide string";
    const std::string text = convert_from_wstring(wText);
    std::cout << text << "\n";

    const std::wstring wtext = convert_to_wstring("Multibyte string");
    std::wcout << wtext << "\n";

    return 0;
}

Jika Anda menggunakan C++11 atau yang lebih baru, lihat std::wstring_convert kelas untuk mengkonversi antara string UTF, misalnya:

std::wstring convert_to_wstring(const std::string &str)
{
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> conv;
    return conv.from_bytes(str);
}

std::string convert_from_wstring(const std::wstring &wstr)
{
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> conv;
    return conv.to_bytes(wstr);
}

Jika Anda perlu berinteraksi dengan kode lain yang didasarkan pada char*/wchar_t*, std::string sebagai konstruktor untuk menerima masukan char* dan metode c_str() yang dapat digunakan untuk keluaran char*, dan hal yang sama berlaku untuk std::wstring dan wchar_t*.

13
Remy Lebeau 14 Maret 2017, 19:04

Cara termudah untuk melakukannya di Windows adalah dengan menggunakan _bstr_ dari

#include <comdef.h> // _bstr_t

#include <string>
#include <iostream>

std::wstring convert_to_wstring(const char* str)
{
    return _bstr_t(str);
}

std::string convert_from_wstring(const WCHAR* wstr)
{
    return _bstr_t(wstr);
}

int main()
{
    const auto text = convert_from_wstring(L"Wide string");
    const auto wide_text = convert_to_wstring("Multibyte string");
    return 0;
}

Juga, perhatikan betapa mudahnya mengembalikan std::wstring dan std::string.

0
Ðаn 14 Maret 2017, 18:30