Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Кросплатформенный Юникод, Вопросы переносимости 
V
    Опции темы
azesmcar
Дата 4.3.2009, 18:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Уважаемые форумчане.

Встал вопрос об использовании юникода в кросплатформенном приложении, т.е. написать все полностью на юникоде. Но вот на какие проблемы я накнулся.

В С++ есть типы wchar_t и std::wstring. Но вопрос в том что в виндоузе и линуксе размеры wchar_t разные. Я так понимаю в виндоузе это юникод (2 байта) в никсах - UTF-32 (4 байта). Как с ним работать? Виндоузовские функции использовать нельзя, данные будут передоватся по сети, братся будут из базы данных MySQL родной драйвер которого тоже очень сомнительно поддерживает wchar_t, т.е. вообще не поддерживает - mysql_query принимает const char*. Но с этим я как нибудь разберусь, вроде нашел решение на сайте MySQL пока не пробовал правда.

Думаю если использовать std::wstring, то использовать его везде и вообще отказатся от std::string, чтобы не мучатся с конвертациями. Но и тут проблема, есть некоторые библиотечные функции которые понятия не имеют что такое юникод, давай им на вход const char* и все тут. Правда тут можно и без юникода, но не очень то красиво когда половина проекта юникод, половина АНСИ.

пока что это, но в процессе я уверен еще возникнут. Может кто нибудь сталкивался с подобным? Я так понимаю C++ и юникод не очень то дружат в плане переносимости да?
PM   Вверх
zim22
Дата 4.3.2009, 18:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 24
Всего: 69





--------------------
PM MAIL   Вверх
azesmcar
Дата 4.3.2009, 18:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



библиотека стороннего производителся - крайний случай. нужен метод средствами стандартного C++. Но все равно спасибо

Добавлено через 6 минут и 39 секунд
да, еще проблема..
std::exception не работает с юникодом. Все стандартные исключение принимают const char*, я не собираюсь писать
Код

throw std::runtime_error(L"Ошибка вышла");

но все же хотелось бы привести программу к одному стандарту, чтобы не было половина юникод, половина анси
PM   Вверх
Alek86
Дата 4.3.2009, 19:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



azesmcar, что нужно будет передать в те библиотечные функции, если у тебя юникодовая строка с китайскими иероглифами?

по поводу исключений - кидай свои, отнаследованные от std::exception


--------------------
user posted image    user posted image
PM MAIL   Вверх
azesmcar
Дата 4.3.2009, 19:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Цитата

azesmcar, что нужно будет передать в те библиотечные функции, если у тебя юникодовая строка с китайскими иероглифами?


Нет, в принципе иероглифы никуда передавать не собираюсь..smile латинские символы только..в принципе мне юникод нужен только для работы с сетью и базой ( так как они будут взаимосвязаны). Но тогда возникнут проблемы с другими частями программы. Переделывать так уж лучше все.
у меня что-то вроде кросплатформенного фреймворка написанного с нуля на чистом С++, нормально работает но с АНСИ, теперь мне его переделывать надо под Юникод из за специфики проекта. 

исключение все наследованы, только вот what возвращяет const char* а не wchar_t, а переопределять возвращяемый тип виртуальной функции нельзя. Но основная проблема все таки с размерами wchar_t, клиент тоже кросплатформенный - очень вероятна ситуация что сервер будет под юникс а клиент под виндоуз и передача информации с сервера в таком случае в юникод формате не видется возможной. Т.е. я сервер отправит 12 байт - что в принципе с его точки зрения строка размером в 3 символа, а для сервера - 6. Да и скорость работы программы в сети интернет критична, возможна огромная нагрузка на сервер. так что нежелательно использование 32х битных символов, тем более что иероглифы поддерживать навряд ли будем. smile максимум русский и несколько еверопейских

Добавлено через 3 минуты и 15 секунд
оффтоп
надо же какие у нас подписи похожие smile

Это сообщение отредактировал(а) azesmcar - 4.3.2009, 19:32
PM   Вверх
pan2004
Дата 4.3.2009, 23:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 357
Регистрация: 28.7.2007

Репутация: 1
Всего: 9



azesmcar, если полностью корректная поддержка уникода не является необходимостью, то можно написать простую функцию преобразования 4х байтовой wstring строки в массив байтов для передачи по сети(где один символ 2 байта) и наоборот В простых случаях старшие байты будут нулями, и их можно просто добавлять/убирать когда надо


--------------------
Qt4/C++ fan
WinXP SP3: MSVC++2005 Qt4.5.1 Boost1.39
сыграем в дурака?
PM MAIL   Вверх
azesmcar
Дата 5.3.2009, 12:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Цитата

azesmcar, если полностью корректная поддержка уникода не является необходимостью, то можно написать простую функцию преобразования 4х байтовой wstring строки в массив байтов для передачи по сети(где один символ 2 байта) и наоборот В простых случаях старшие байты будут нулями, и их можно просто добавлять/убирать когда надо


этот вариант тоже один из крайних, потому что в базу эти строки уже не запихнешь, надо менять кодировку. На данный момент пишу преобразование UTC - UTF8. Думаю буду переделывать все строки в UTF8. Но все равно всем большое спасибо, я так понял стандартного ответа для этой ситуации не существует smile 
PM   Вверх
Torsten
Дата 5.3.2009, 12:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 10.6.2008
Где: Pskov

Репутация: 3
Всего: 7



Те проще работать с char, и самому все преобразования делать - тогда получится кросс-платформенно и без библиотек строннего производителя. 
typedef std::vector<char> UtfString;

Ты только должен знать, какая кодировка на входе и какая на выходе и преобразования делать.
--------------------
We have no begining, we have no end. We are infinite.
PM MAIL   Вверх
Alek86
Дата 5.3.2009, 12:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



azesmcar, может попробуешь создать 2 собственных класса строк - для внутреннего и внешнего использования?
так чтобы класс для внутреннего использования имел функцию преобразования в char*, а внешний имел на любой платформе одинаковое побитовое.
тогда останется только добавить функции преобразования из одного в другой
(кстати, при реализации этих функций можно буудет увидеть все подводные камни, что бы не заметил при использовании wchar_t* и char*)


оффтоп
а подпись я у тя и скоммуниздил когда-то давно, заменив картинки линками smile


--------------------
user posted image    user posted image
PM MAIL   Вверх
azesmcar
Дата 5.3.2009, 13:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Torsten
Цитата

typedef std::vector<char> UtfString;


ну наверное не совсем вектор, но специализировать std::string можно. 

Alek86, для внутреннего мне std::string а хватит..а для внешнего наверное так и поступлю. Специализирую basic_string для типа short и напишу для него функцию конвертации в UTF-8 (std::string) - над чем сейчас и ломаю голову.. если у кого есть - поделитесь, башка трещит уже от этих нулей и едениц smile

Добавлено через 3 минуты и 38 секунд
в интернете нашел парочку реализаций, работают не нормально и не оптимально...я пытаюсь сделать только с помощью битовых операций.

Цитата

оффтоп
а подпись я у тя и скоммуниздил когда-то давно, заменив картинки линками smile 

оффтом smile

только заметил что у меня ссылок нет smile исправлено, спасибо. Уже было самое время обновлять результаты.

PM   Вверх
azesmcar
Дата 5.3.2009, 13:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



кстати поскольку проблема потихоньку находит решение добавлю материалы от себя

http://ru.wikipedia.org/wiki/UTF-8 - стандарт UTF-8

исходники добавлю когда заработает для китайского smile т.е. после багфиксинга 
PM   Вверх
azesmcar
Дата 5.3.2009, 14:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



решил сделать немнго по другому..у меня в фреймворке написан шаблон конвертера типов и как оболочка для него - lexical_cast.
код конвертации в последней специализации шаблона...какие нибудь умозаключения по этому поводу есть? может как нибудь можно улучшить?

Код

#include <iostream>
#include <sstream>
#include <string>

namespace types
{
    template <class To, class From>
    class TypeConverter
    {
    public:
        static To Convert(const From& from) {
            std::stringstream stream;
            stream << from;
            To value;

            //Check if stream is bad
            if ( stream.bad() )
            {
                throw std::bad_exception();
            }

            //Check if stream contains variable type you want to get
            if ((stream >> value).fail() || !stream.eof())
            {
                throw std::bad_cast();
            }

            return value;
        }
    };

    template <class From>
    class TypeConverter<std::string, From>
    {
    public:
        static std::string Convert(const From& from) {
            std::stringstream stream;
            stream << from;
            return stream.str();
        }
    };

    template <>
    class TypeConverter<std::string, std::string>
    {
    public:
        static std::string Convert(const std::string& from) {
            return from;
        }
    };

    template <>
    class TypeConverter<std::string, std::wstring>
    {
    public:
        static std::string Convert(const std::wstring& from) {
            std::string result;
            for (std::wstring::const_iterator it = from.begin(); it != from.end(); ++it)
            {
                short nchar = *it;
                if (nchar <= 0x7F) {
                    result += (char)*it;
                } else if (nchar <= 0x07FF) {
                    result += (0xC0 | (nchar >> 6));
                    result += (0x80 | (nchar & 0x3F));
                } else if (nchar <= 0xFFFF) {
                    result += (0xE0 | (nchar >> 12));
                    result += (0x80 | ((nchar >> 6) & 0x3F));
                    result += (0x80 | (nchar & 0x3F));
                } else if (*it <= 0x1FFFFF) {
                    result += (0xF0 | (nchar >> 18));
                    result += (0x80 | ((nchar >> 12) & 0x3F));
                    result += (0x80 | ((nchar >> 6) & 0x3F));
                    result += (0x80 | (nchar & 0x3F));
                }
            }
            return result;
        }
    };

    //lexical_cast function for all types which supports stream I/O
    template <class T, class U>
    T lexical_cast(const U& from) {
        return TypeConverter<T, U>::Convert( from );
    }
}

int main()
{
    std::wstring text = L"здравствуйте дорогой - 中文, привет Мао Дзедуну!!!";
    std::cout << types::lexical_cast<std::string>(text) << std::endl;
}


PM   Вверх
azesmcar
Дата 5.3.2009, 15:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Код

    template <>
    class TypeConverter<std::wstring, std::string>
    {
    public:
        static std::wstring Convert(const std::string& from) {
            std::wstring result;
            unsigned char nchar;
            wchar_t tmp;
            for (std::string::const_iterator it = from.begin(); it != from.end(); ++it)
            {
                nchar = (unsigned char)*it;
                if (nchar <= 0x7F) {
                    tmp = nchar;
                } else if ((nchar & 0xE0) == 0xC0) {
                    tmp = (nchar & 0x1F) << 6;
                    nchar = (unsigned char)*(++it);
                    tmp |= nchar & 0x3F;
                } else if ((nchar & 0xF0) == 0xE0) {
                    tmp = (nchar & 0x0F) << 12;
                    nchar = (unsigned char)*(++it);
                    tmp |= (nchar & 0x3F) << 6;
                    nchar = (unsigned char)*(++it);
                    tmp |= (nchar & 0x3F);
                } else if ((nchar & 0xF1) == 0xF0) {
                    tmp = (nchar & 0x0F) << 18;
                    nchar = (unsigned char)*(++it);
                    tmp |= (nchar & 0x3F) << 12;
                    nchar = (unsigned char)*(++it);
                    tmp |= (nchar & 0x3F) << 6;
                    nchar = (unsigned char)*(++it);
                    tmp |= (nchar & 0x3F);
                }
                result += tmp;
            }
            return result;
        }
    };


и его обратное преобразование...

Пример
Код

    std::wstring text = L"здравствуйте дорогой - 中文, привет Мао Дзедуну!!!";
    std::string utf8 = types::lexical_cast<std::string>(text);
    std::wstring wstr = types::lexical_cast<std::wstring>(utf8);

    if (text != wstr)
        std::cout << "Kernel Panic!!!" << std::endl;

PM   Вверх
chaos
Дата 6.3.2009, 15:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Серийный программист
****


Профиль
Группа: Завсегдатай
Сообщений: 2979
Регистрация: 7.7.2004
Где: Екатеринбург

Репутация: 6
Всего: 44



Цитата(azesmcar @ 5.3.2009,  12:36)
Код

...
std::cout << "Kernel Panic!!!" << std::endl;
...

Сильно smile
PM WWW   Вверх
Quartz
Дата 8.3.2009, 16:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 40
Регистрация: 28.6.2008

Репутация: 1
Всего: 4



Цитата(azesmcar @  4.3.2009,  19:30 Найти цитируемый пост)
Но основная проблема все таки с размерами wchar_t, клиент тоже кросплатформенный - очень вероятна ситуация что сервер будет под юникс а клиент под виндоуз и передача информации с сервера в таком случае в юникод формате не видется возможной.

В gcc есть ключ -fshort-wchar (2-байтовые wchar_t).
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0942 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.