C++ C++;将UTF8字符数组转换为CP1250

C++ C++;将UTF8字符数组转换为CP1250,c++,visual-studio,static-libraries,iconv,C++,Visual Studio,Static Libraries,Iconv,我在将UTF8编码的字符数组转换为CP1250编码的字符数组时遇到问题 我尝试创建一个静态iconv库,但在编译UTF8->CP1250代码时,它总是失败 1>foo.obj : error LNK2001: unresolved external symbol libiconv_close 1>foo.obj : error LNK2001: unresolved external symbol libiconv_open 1>foo.obj : error LNK2001:

我在将UTF8编码的字符数组转换为CP1250编码的字符数组时遇到问题

我尝试创建一个静态iconv库,但在编译UTF8->CP1250代码时,它总是失败

1>foo.obj : error LNK2001: unresolved external symbol libiconv_close
1>foo.obj : error LNK2001: unresolved external symbol libiconv_open
1>foo.obj : error LNK2001: unresolved external symbol libiconv
我还尝试了许多编译过的静态库,但总是出现相同的错误

无论是否设置了
/MD
/MT


我不坚持使用iconv。这个问题还有其他简单的解决办法吗?谢谢

既然您在Windows中编码,为什么不使用Windows API呢。使用
MultiByteToWideChar
将无损转换为UTF-16。然后使用
WideCharToMultiByte
向下转换为例如CP 1250


附录:下面的代码似乎正常工作

#include <assert.h>             // assert
#include <iostream>             // std::wcout, std::wcerr
#include <iterator>             // std::begin, std::end
#include <string>               // std::string, std::wstring
#include <stddef.h>             // ptrdiff_t
#include <stdexcept>            // std::system_error
#include <stdlib.h>             // EXIT_SUCCESS
#include <string.h>             // memcmp
#include <system_error>         // std::system_error etc.

// Example of how to include Microsoft's <windows.h>.
// More support stuff is generally needed for more serious code.
#undef UNICODE
#define UNICODE
#undef NOMINMAX
#define NOMINMAX
#undef STRICT
#define STRICT
#include <windows.h>            // E_FAIL, etc.

namespace cppx {
    using std::begin;
    using std::end;
    using std::error_code;
    using std::string;
    using std::system_error;
    using std::system_category;

    typedef unsigned char   Byte;
    typedef ptrdiff_t       Size;

    template< class Type >
    auto size( Type const& c )
        -> Size
    { return end( c ) - begin( c ); }

    auto hopefully( bool const condition ) -> bool { return condition; }

    auto fail(
        string const&   message,
        int const       code    = 0
        )
        -> bool
    {
        throw system_error(
            error_code( code, system_category() ), message
            );
    }
}  // namespace cppx

namespace data {
    using cppx::Byte;
    using cppx::hopefully;
    using cppx::fail;
    using std::string;
    using std::wstring;

    char const utf8_bom[] = "\xEF\xBB\xBF";

    template< class Type, int n >
    auto dummy()
        -> Type&
    { static Type the_dummy; return the_dummy; }

    auto utf16_from_utf8( char const* bytes, int length )
        -> wstring
    {
        if( length >= 3 && ::memcmp( bytes, utf8_bom, 3 ) == 0 )
        {
            bytes += 3;  length -= 3;
        }

        assert( length >= 0 );
        if( length == 0 ) { return L""; }

        int const buffer_size = ::MultiByteToWideChar(
            CP_UTF8,
            0,                  // flags, must be 0 for UTF-8
            bytes,
            length,
            nullptr,            // output buffer
            0                   // buffer size
            );
        hopefully( buffer_size > 0 )
            || fail( "MultiByteToWideChar (1st call)", ::GetLastError() );

        wstring result( buffer_size, L'#' );
        int const n_encoding_values = ::MultiByteToWideChar(
            CP_UTF8,
            0,                  // flags, must be 0 for UTF-8
            bytes,
            length,
            &result[0],         // output buffer
            buffer_size
            );
        hopefully( n_encoding_values > 0 )
            || fail( "MultiByteToWideChar (2nd call)", ::GetLastError() );
        assert( n_encoding_values <= buffer_size );

        result.resize( n_encoding_values );     // Possible down-sizing.
        return result;
    }

    auto utf16_from_utf8( Byte const* const bytes, int const length )
        -> wstring
    {
        return utf16_from_utf8( reinterpret_cast<char const*>( bytes ), length );
    }

    auto sbcs_from(
        wchar_t const* const    s,
        int const               length,
        unsigned const          codepage            = ::GetACP(),
        bool&                   used_default_char   = dummy<bool, 1>()
        )
        -> string
    {
        assert( codepage != CP_UTF8 );
        if( length == 0 ) { return ""; }

        DWORD const         flags           = WC_NO_BEST_FIT_CHARS;     // Must be 0 for UTF-8.
        char const* const   default_char    = "\x7F";                   // ASCII DEL

        int const buffer_size = WideCharToMultiByte(
            codepage,
            flags,
            s,
            length,
            nullptr,            // buffer
            0,                  // buffer size
            default_char,
            nullptr
            );
        hopefully( buffer_size > 0 )
            || fail( "WideCharToMultiByte (1st call)", ::GetLastError() );

        string  result              = string( buffer_size, '#' );
        BOOL    defaulted           = false;
        int const n_bytes = WideCharToMultiByte(
            codepage,
            flags,
            s,
            length,
            &result[0],         // buffer
            buffer_size,
            default_char,
            &defaulted
            );
        hopefully( n_bytes > 0 )
            || fail( "WideCharToMultiByte (2nd call)", ::GetLastError() );
        assert( n_bytes <= buffer_size );

        result.resize( n_bytes );
        used_default_char = !!defaulted;
        return result;
    }

    auto sbcs_from(
        wstring const&          s,
        unsigned const          codepage            = ::GetACP(),
        bool&                   used_default_char   = dummy<bool, 1>()
        )
        -> string
    {
        if( s.length() == 0 ) { return ""; }
        return sbcs_from( &s[0], s.length(), codepage, used_default_char );
    }

}  // namespace data

void cpp_main()
{
    using cppx::Byte;
    using cppx::fail;
    using cppx::size;
    using std::string;
    using std::wstring;

    auto const infobox      = MB_ICONINFORMATION | MB_SETFOREGROUND;
    Byte const utf8_bytes[] = // UTF-8 with BOM, as if from a file.
    {
        0xEF, 0xBB, 0xBF, 0x42, 0x6C, 0xC3, 0xA5, 0x62, 0xC3, 0xA6,
        0x72, 0x73, 0x79, 0x6C, 0x74, 0x65, 0x74, 0xC3, 0xB8, 0x79,
        0x21, 0x20, 0xE6, 0x97, 0xA5, 0xE6, 0x9C, 0xAC, 0xE5, 0x9B,
        0xBD, 0x20, 0xD0, 0xBA, 0xD0, 0xBE, 0xD1, 0x88, 0xD0, 0xBA,
        0xD0, 0xB0, 0x21, 0x0D, 0x0A, 0x0D, 0x0A, 0x48, 0x75, 0x6E,
        0x67, 0x61, 0x72, 0x69, 0x61, 0x6E, 0x20, 0x61, 0x6C, 0x70,
        0x68, 0x61, 0x62, 0x65, 0x74, 0x3A, 0x0D, 0x0A, 0x41, 0x20,
        0xC3, 0x81, 0x20, 0x42, 0x20, 0x43, 0x20, 0x43, 0x73, 0x20,
        0x44, 0x20, 0x44, 0x7A, 0x20, 0x44, 0x7A, 0x73, 0x20, 0x45,
        0x20, 0xC3, 0x89, 0x20, 0x46, 0x20, 0x47, 0x20, 0x47, 0x79,
        0x20, 0x48, 0x20, 0x49, 0x20, 0xC3, 0x8D, 0x20, 0x4A, 0x20,
        0x4B, 0x20, 0x4C, 0x20, 0x4C, 0x79, 0x20, 0x4D, 0x20, 0x4E,
        0x0D, 0x0A, 0x4E, 0x79, 0x20, 0x4F, 0x20, 0xC3, 0x93, 0x20,
        0xC3, 0x96, 0x20, 0xC5, 0x90, 0x20, 0x50, 0x20, 0x28, 0x51,
        0x29, 0x20, 0x52, 0x20, 0x53, 0x20, 0x53, 0x7A, 0x20, 0x54,
        0x20, 0x54, 0x79, 0x20, 0x55, 0x20, 0xC3, 0x9A, 0x20, 0xC3,
        0x9C, 0x20, 0xC5, 0xB0, 0x20, 0x56, 0x20, 0x28, 0x57, 0x29,
        0x20, 0x28, 0x58, 0x29, 0x20, 0x28, 0x59, 0x29, 0x20, 0x5A,
        0x20, 0x5A, 0x73, 0x0D, 0x0A
    };

    wstring const text = data::utf16_from_utf8( utf8_bytes, size( utf8_bytes ) );
    ::MessageBox( 0, text.c_str(), L"Original text:", infobox );

    string const    sbcs_text           = data::sbcs_from( text, 1250 );

    WORD const      hungarian           = MAKELANGID(
        LANG_HUNGARIAN, SUBLANG_HUNGARIAN_HUNGARY
        );
    DWORD const     hungarian_locale_id = MAKELCID( hungarian, SORT_DEFAULT );

    SetThreadLocale( hungarian_locale_id )
        || fail( "SetThreadLocale", ::GetLastError() );
    DWORD thread_cp = 0;
    ::GetLocaleInfo(
        ::GetThreadLocale(),    // Not LOCALE_USER_DEFAULT,
        LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
        reinterpret_cast<wchar_t*>( &thread_cp ),
        sizeof( thread_cp )/sizeof( wchar_t )
        )
        || fail( "GetLocaleInfo", ::GetLastError() );
    //::MessageBox( 0, std::to_wstring( thread_cp ).c_str(), L"Codepage:", MB_SETFOREGROUND );
    assert( thread_cp == 1250 );
    ::MessageBoxA( 0, sbcs_text.c_str(), "SBCS codepage 1250 text:", infobox );
}

auto main()
    -> int
{
    using namespace std;
    try
    {
        cpp_main();
        return EXIT_SUCCESS;
    }
    catch( system_error const& x )
    {
        auto const code = x.code().value();
        cerr << "!" << x.what() << " (code: " << code << ")" << endl;
        return code;
    }
    catch( exception const& x )
    {
        cerr << "!" << x.what() << endl;
        return E_FAIL;
    }
}
#包含//断言
#包括//std::wcout、std::wcerr
#包括//标准::开始,标准::结束
#包括//std::string、std::wstring
#包括//ptrdiff\t
#包括//标准::系统错误
#包括//退出\成功
#包括//memcmp
#包括//标准::系统错误等。
//如何包含Microsoft的示例。
//对于更严肃的代码,通常需要更多的支持材料。
#未定义UNICODE
#定义UNICODE
#未定义NOMINMAX
#定义NOMINMAX
#未定义严格
#定义严格
#包括//E\u失败等。
命名空间cppx{
使用std::begin;
使用std::end;
使用std::error\u代码;
使用std::string;
使用std::系统错误;
使用std::system_类别;
typedef无符号字符字节;
typedef ptrdiff\t大小;
模板<类类型>
自动大小(const&c类型)
->大小
{返回结束(c)-开始(c);}
自动(布尔常量条件)->bool{return condition;}
自动失效(
字符串常量和消息,
int常量代码=0
)
->布尔
{
抛出系统错误(
错误代码(代码,系统类别()),消息
);
}
}//名称空间cppx
命名空间数据{
使用cppx::Byte;
使用cppx::希望;
使用cppx::fail;
使用std::string;
使用std::wstring;
字符常量utf8\U bom[]=“\xEF\xBB\xBF”;
模板<类类型,int n>
自动虚拟()
->类型&
{静态键入_伪;返回_伪;}
从utf8自动执行utf16(字符常量*字节,整数长度)
->威斯汀
{
如果(长度>=3&&::memcmp(字节,utf8\U bom,3)==0)
{
字节+=3;长度-=3;
}
断言(长度>=0);
如果(长度==0){返回L”“;}
int const buffer_size=::MultiByteToWideChar(
CP_UTF8,
0,//标志对于UTF-8必须为0
字节,
长度,
nullptr,//输出缓冲区
0//缓冲区大小
);
希望(缓冲区大小>0)
||失败(“MultiByteToWideChar(第一次调用)”,::GetLastError();
wstring结果(缓冲区大小,L'#');
int const n_编码值=::MultiByteToWideChar(
CP_UTF8,
0,//标志对于UTF-8必须为0
字节,
长度,
&结果[0],//输出缓冲区
缓冲区大小
);
希望(n_编码值>0)
||失败(“MultiByteToWideChar(第二次调用)”,::GetLastError();
断言(n\u编码\u值)
{
从utf8返回utf16(重新解释转换(字节),长度);
}
自动sbcs_从(
wchar_t const*const s,
int常量长度,
无符号常量代码页=::GetACP(),
bool&used\u default\u char=dummy()
)
->串
{
断言(代码页!=CP_UTF8);
如果(长度==0){return”“;}
DWORD const flags=WC\u NO\u BEST\u FIT\u CHARS;//对于UTF-8必须为0。
char const*const default_char=“\x7F”//ASCII DEL
int const buffer_size=WideCharToMultiByte(
代码页,
旗帜,
s
长度,
nullptr,//缓冲区
0,//缓冲区大小
默认字符,
nullptr
);
希望(缓冲区大小>0)
||失败(“WideChartMultiByte(第一次调用)”,::GetLastError();
字符串结果=字符串(缓冲区大小“#”);
BOOL defaulted=false;
int const n_bytes=宽图表多字节(
代码页,
旗帜,
s
长度,
&结果[0],//缓冲区
缓冲区大小,
默认字符,
&违约
);
希望(n_字节>0)
||失败(“WideChartMultiByte(第二次调用)”,::GetLastError();
断言(n_字节)字符串
{
如果(s.length()==0){return”“;}
从(&s[0],s.length(),代码页,used_default_char)返回sbcs_;
}
}//名称空间数据
无效cpp_main()
{
使用cppx::Byte;
使用cppx::fail;
使用cppx::size;
使用std::string;
使用std::wstring;
自动常量信息框=MB|U图标信息| MB|U设置前景;
字节常量utf8_bytes[]=//带BOM的UTF-8,就像来自文件一样。
{
0xEF、0xBB、0xBF、0x42、0x6C、0xC3、0xA5、0x62、0xC3、0xA6、,
0x72、0x73、0x79、0x6C、0x74、0x65、0x74、0xC3、0xB8、0x79、,
0x21、0x20、0xE6、0x97、0xA5、0xE6、0x9C、0xAC、0xE5、0x9B、,
0xBD,0x20,0xD0,0xBA,0xD0,0xBE,0xD1,0x88,0xD0,0xBA,
0xD0、0xB0、0x21、0x0D、0x0A、0x0D、0x0A、0x48、0x75、0x6E、,
0x67、0x61、0x72、0x69、0x61、0x6E、0x20、0x61、0x6C、0x70,
0x68、0x61、0x62、0x65、0x74、0x3A、0x0D、0x0A、0x41、0x20,
0xC3、0x81、0x20、0x42、0x20、0x43、0x20、0x43、0x73、0x20、,