Подтвердить что ты не робот

Преобразовать wchar_t в char

Мне было интересно, безопасно ли это сделать?

wchar_t wide = /* something */;
assert(wide >= 0 && wide < 256 &&);
char myChar = static_cast<char>(wide);

Если я уверен, что широкий char попадет в диапазон ASCII.

4b9b3361

Ответ 1

assert предназначен для обеспечения того, что что-то истинно в режиме отладки, без какого-либо эффекта в сборке релиза. Лучше использовать оператор if и иметь альтернативный план для символов, находящихся за пределами диапазона, если только единственный способ получить символы вне диапазона - это ошибка программы.

Кроме того, в зависимости от кодировки символов вы можете найти разницу между символами Unicode от 0x80 до 0xff и версией char.

Ответ 2

Почему бы просто не использовать библиотечную процедуру wcstombs.

Ответ 3

Вы ищете wctomb(): он по стандарту ANSI, поэтому вы можете рассчитывать на него. Он работает, даже если wchar_t использует код выше 255. Вы почти наверняка не хотите его использовать.


wchar_t является интегральным типом, поэтому ваш компилятор не будет жаловаться, если вы действительно выполните:

char x = (char)wc;

но поскольку он является интегральным типом, нет абсолютно никаких оснований для этого. Если вы случайно прочитали Herbert Schildt C: The Complete Reference или любую книгу C на основе этого, тогда вы полностью и грубо дезинформировали. Символы должны быть типа int или лучше. Это означает, что вы должны написать это:

int x = getchar();

а не это:

char x = getchar(); /* <- WRONG! */

Что касается интегральных типов, то char бесполезно. Вы не должны создавать функции, которые принимают параметры типа char, и вы не должны создавать временные переменные типа char, а также те же рекомендации для wchar_t.

char* может быть удобным typedef для символьной строки, но это ошибка начинающего, чтобы думать об этом как о "массиве символов" или "указателе на массив символов" - несмотря на то, что cdecl говорит инструмент. Рассмотрение его как фактического массива символов с такими же нонсенсами:

for(int i = 0; s[i]; ++i) {
  wchar_t wc = s[i];
  char c = doit(wc);
  out[i] = c;
}

абсурдно неправильно. Он не будет делать то, что вы хотите; он будет ломаться тонким и серьезным образом, вести себя по-разному на разных платформах, и вы наверняка сбиваете с толку своих пользователей. Если вы видите это, вы пытаетесь переопределить wctombs(), который уже является частью ANSI C уже, , но он все еще ошибочен.

Вы действительно ищете iconv(), который преобразует строку символов из одной кодировки (даже если она упакована в wchar_t array), в строку символов другой кодировки.

Теперь перейдите к this, чтобы узнать, что неправильно с iconv.

Ответ 4

Короткая функция, которую я написал некоторое время назад, чтобы упаковать массив wchar_t в массив char. Символы, которые не находятся на кодовой странице ANSI (0-127), заменяются символом '?' символов, и он правильно обрабатывает суррогатные пары.

size_t to_narrow(const wchar_t * src, char * dest, size_t dest_len){
  size_t i;
  wchar_t code;

  i = 0;

  while (src[i] != '\0' && i < (dest_len - 1)){
    code = src[i];
    if (code < 128)
      dest[i] = char(code);
    else{
      dest[i] = '?';
      if (code >= 0xD800 && code <= 0xD8FF)
        // lead surrogate, skip the next code unit, which is the trail
        i++;
    }
    i++;
  }

  dest[i] = '\0';

  return i - 1;

}

Ответ 5

Технически "char" может иметь тот же диапазон, что и "signed char" или "unsigned char". Для символов без знака ваш диапазон правильный; теоретически, для подписанных символов, ваше состояние неверно. На практике очень немногие компиляторы будут возражать - и результат будет таким же.

Nitpick: последний && в assert является синтаксической ошибкой.

Является ли это утверждение подходящим, зависит от того, можете ли вы позволить себе сбой при получении кода клиенту, и что вы могли бы или должны делать, если условие утверждения нарушено, но утверждение не скомпилировано в код. Для работы отладки это кажется прекрасным, но вам может понадобиться активный тест после него для проверки времени выполнения.

Ответ 6

можно также преобразовать wchar_t → wstring → string → char

wchar_t wide;
wstring wstrValue;
wstrValue[0] = wide

string strValue;
strValue.assign(wstrValue.begin(), wstrValue.end());  // convert wstring to string

char char_value = strValue[0];

Ответ 7

В общем, нет. int(wchar_t(255)) == int(char(255)), конечно, но это означает, что они имеют одинаковую стоимость int. Они не могут представлять одни и те же символы.

Вы даже увидите такое несоответствие на большинстве ПК с ОС Windows. Например, на стр. 1250 кода Windows char(0xFF) имеет тот же символ, что и wchar_t(0x02D9) (точка выше), а не wchar_t(0x00FF) (малая y с диарезисом).

Обратите внимание, что он даже не поддерживается для диапазона ASCII, так как С++ даже не требует ASCII. В системах IBM, в частности, вы можете увидеть, что 'A' != 65

Ответ 8

Вот еще один способ сделать это, не забудьте использовать free() для результата.

char* wchar_to_char(const wchar_t* pwchar)
{
    // get the number of characters in the string.
    int currentCharIndex = 0;
    char currentChar = pwchar[currentCharIndex];

    while (currentChar != '\0')
    {
        currentCharIndex++;
        currentChar = pwchar[currentCharIndex];
    }

    const int charCount = currentCharIndex + 1;

    // allocate a new block of memory size char (1 byte) instead of wide char (2 bytes)
    char* filePathC = (char*)malloc(sizeof(char) * charCount);

    for (int i = 0; i < charCount; i++)
    {
        // convert to char (1 byte)
        char character = pwchar[i];

        *filePathC = character;

        filePathC += sizeof(char);

    }
    filePathC += '\0';

    filePathC -= (sizeof(char) * charCount);

    return filePathC;
}