Разница между неподписанным символом и указателем на символ - PullRequest
4 голосов
/ 10 февраля 2012

Меня немного смущают различия между unsigned char (что также BYTE в WinAPI) и char указателями.

В настоящее время я работаю с некоторыми ATL-ориентированнымистарый код, и я вижу много выражений, таких как:

CAtlArray<BYTE> rawContent;
CALL_THE_FUNCTION_WHICH_FILLS_RAW_CONTENT(rawContent);
return ArrayToUnicodeString(rawContent);
// or return ArrayToAnsiString(rawContent);

Теперь реализации ArrayToXXString выглядят следующим образом:

CStringA ArrayToAnsiString(const CAtlArray<BYTE>& array)
{
    CAtlArray<BYTE> copiedArray;
    copiedArray.Copy(array);
    copiedArray.Add('\0');

    // Casting from BYTE* -> LPCSTR (const char*).
    return CStringA((LPCSTR)copiedArray.GetData());
}

CStringW ArrayToUnicodeString(const CAtlArray<BYTE>& array)
{
    CAtlArray<BYTE> copiedArray;
    copiedArray.Copy(array);

    copiedArray.Add('\0');
    copiedArray.Add('\0');

    // Same here.        
    return CStringW((LPCWSTR)copiedArray.GetData());
}

Итак, вопросы:

  • Является ли приведение в стиле C от BYTE* до LPCSTR (const char*) безопасным для всех возможных случаев?

  • Действительно ли необходимо добавить double null-termination при преобразовании данных массива в строку широких символов?

  • Преобразованиерутина CStringW((LPCWSTR)copiedArray.GetData()) кажется мне недействительной, это правда?

  • Есть ли способ облегчить понимание и поддержку всего этого кода?

Ответы [ 4 ]

3 голосов
/ 10 февраля 2012

Стандарт C довольно странный, когда речь заходит об определении байта.У вас есть пара гарантий, хотя.

  • Байт всегда будет иметь один символ размером
    • sizeof (char) всегда возвращает 1
  • Байт будет по крайней мере 8биты размером

Это определение плохо сочетается со старыми платформами, где длина байта составляла 6 или 7 бит, но это означает, что BYTE*, и char * гарантированно эквивалентны.

В конце строки Unicode необходимы несколько нулей, поскольку существуют допустимые символы Unicode, начинающиеся с нулевого (нулевого) байта.

Что касается упрощения чтения кода, то это полностьювопрос стиля.Этот код, кажется, написан в стиле, используемом большим количеством старого кода на C Windows, который определенно потерял популярность.Вероятно, есть множество способов сделать это более ясным для вас, но как сделать это более ясным, ясного ответа нет.

2 голосов
/ 10 февраля 2012
  • Да, это всегда безопасно.Потому что они оба указывают на массив однобайтовых областей памяти.
    LPCSTR: строка с длинным указателем на константу (однобайтовая)
    LPCWSTR: строка с длинным указателем на константа (многобайтовая)
    LPCTSTR: контекстно-зависимая (длинная или многобайтовая) строка с длинным указателем на Const

  • В строках широких символов каждый отдельный символ занимает 2 байта памяти, идлина ячейки памяти, содержащей строку, должна быть кратна 2. Поэтому, если вы хотите добавить широкий '\ 0' в конец строки, вы должны добавить два байта.

  • Извините за эту часть, я не знаю ATL и не могу помочь вам в этой части, но на самом деле я не вижу здесь никакой сложности, и я думаю, что ее легко обслуживать.Какой код вы действительно хотите сделать проще для понимания и поддержки?

1 голос
/ 10 февраля 2012
  1. Если BYTE * ведет себя как правильная строка (то есть последний BYTE равен 0), вы можете привести BYTE * к LPCSTR, да.Функции, работающие с LPCSTR, предполагают строки с нулевым символом в конце.
  2. Я думаю, что множественные нули необходимы только при работе с некоторыми многобайтовыми наборами символов.Наиболее распространенные 8-битные кодировки (как обычные Windows Western, а также UTF-8) не требуют их.
  3. CString - лучшая попытка Microsoft создать удобные для пользователя строки.Например, его конструктор может обрабатывать ввод как char, так и wchar_t независимо от того, широка ли сама CString или нет, поэтому вам не нужно сильно беспокоиться о преобразовании.

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

0 голосов
/ 10 февраля 2012

LPCWSTR - это строка с 2 байтами на символ, символ "char" - один байт на символ.Это означает, что вы не можете привести его в C-стиле, потому что вам нужно настроить память (добавить «0» перед каждым стандартом-ASCII), а не просто читать данные по-другому из памяти (что такое C-Cast).сделал бы).Так что актеры не так безопасны, я бы сказал.

Двойное обнуление: у вас всегда есть 2 байта как один символ, поэтому ваш знак "конец строки" должен быть длиной 2 байта.

Чтобы облегчить понимание этого кода, поищите lexical_cast в Boost (http://www.boost.org/doc/libs/1_48_0/doc/html/boost_lexical_cast.html)

). Другой способ - использовать std :: strings (например, std :: basic_string;), и выможет выполнять над строковыми операциями.

...