2011-12-14 2 views
0

Почему массивы char останавливаются прямо перед обнаружением байта 0x00 и как можно избежать этой проблемы (возможно, используя другой тип данных (какой и почему) или «трюк» с char)?0x00 и char arrays

Например, в следующем коде, выход «а» только, остальные байты не отображаются:

unsigned char cbuffer[]={0x61,0x00,0x62,0x63,0x0}; 
std::string sbuffer=reinterpret_cast<const char*>(cbuffer); 

cout << sbuffer << endl; 

Аналогично в следующем коде, выход «AB»:

unsigned char cbuffer[]={0x61,0x62,0x00,0x63,0x0}; 
std::string sbuffer=reinterpret_cast<const char*>(cbuffer); 

Простые и эффективные обходные пути проблемы (где 0x00 хранится в массиве как обычный байт).

+4

Ummm. Поскольку строки в C являются массивами символов, завершенных нулевым байтом? –

+0

std :: vector с перегруженным оператором << (ostream &, const vector &) '. – moshbear

+0

@HeathHunnicutt: Не обязательно. Нередко не использовать конечные нули. Сам язык требует только строки _literals_. Библиотеки также могут потребовать его, но это не одно и то же. –

ответ

5

Общепринято в C передавать строки в виде указателей на нуль-оконечные char массивы. null представлен 0x00. Чтобы упростить преобразование, std::string можно построить с помощью указателя на массив символов с нулевым завершением, что и происходит с вашим кодом. Но когда он находит нуль, он думает, что это конец строки. Если у вас cout массив массива напрямую, вы обнаружите, что он делает то же самое предположение, потому что у них нет другого способа определить конец строки, на которую указывает char*. (Теоретически они могли бы рассказать длину в вашем случае, если они понимали char (&)[], но почти ничего в стандартной библиотеке не печально).

Намеченные обходные пути, чтобы использовать этот конструктор вместо:

int len = sizeof(cbuffer)/sizeof(cbuffer[0]); 
std::string sbuffer(cbuffer, len); //5 characters in cbuffer, 1 byte each 

или

int len = sizeof(cbuffer)/sizeof(cbuffer[0]); 
std::cout.write(cbuffer, len); //5 characters in buffer, 1 byte each 

Однако, вы должны быть осторожны с sizeof(cbuffer). Если cbuffer - это char* (указатель) вместо char(&)[] (массив), то sizeof(ptr) вернет неправильное значение, и нет возможности получить правильную длину в этой точке, если строка не заканчивается на нуль.

+1

Это хорошо, за исключением того, что не рекомендуется использовать значение 'sizeof' для определения длины буфера. –

+0

@MarkB: У меня на самом деле было это вначале, но потом удалил его из-за общего «почему sizeof (ptr) возвращает 4, у меня есть 10 букв!». Я отредактирую ответ, чтобы описать плюсы и минусы. –

+0

"_NULL-terminated_" NUL! – curiousguy

2

символьные массивы не делать ничего

В C строковые функции используют 0, чтобы отметить конец строки.
std :: cout перегружен для массивов символов, чтобы напечатать их как строки «c», если вы хотите распечатать отдельные значения, вам нужно выполнить цикл над значениями, вы также можете вывести их как std :: hex

В этом случае вы создаете std :: String из массива char 'c', поэтому ctor строки std :: предполагает, что строки 'c' заканчиваются на '0'. Поскольку он только передал адрес в памяти, как еще он может знать, где заканчивается строка?

пс. Если вы хотите сохранить массив байтов, вы, вероятно, должны использовать std :: vector

+0

То же самое относится к управляемым строкам? 'System :: String' –

+0

он не' cout' массив символов, он 'cout' объект 'std :: string', который не имеет этой проблемы. –

0

0x00 - символ без печати, 0..0x20, все не печатаются char s, хотя некоторые из них служат разрывами строк. 0x00 служит для завершения строки.

1

Попытка:

#include <iostream> 
#include <string> 

int main() 
{ 

    unsigned char cbuffer[]={0x61,0x62,0x00,0x63,0x0}; 

    // Here s1 is treating the cBuffer as a C-String 
    // Thus it will only read upto the first '\0' character 
    std::string s1(reinterpret_cast<const char*>(cbuffer)); 
    std::cout << s1 << "\n"; 

    // Here s2 is treating the cBuffer as an array. 
    // It reads the specified length into the string. 
    std::string s2(reinterpret_cast<const char*>(cbuffer), sizeof(cbuffer)/sizeof(cbuffer[0])); 

    // Note: How std::cout prints the '\0' character may leave it empty. 
    std::cout << s2 << "\n"; 

} 
1

0x00 байт используется в качестве дозорных, чтобы отметить конец строки в C. Весь массив, однако, остается в памяти. Вы можете использовать альтернативный конструктор для std::string, если хотите, чтобы строка содержала весь массив символов.Но печать этой строки все равно даст вам только «ab». Это решение представлять строки C таким образом является одним из тех решений arbitrary, за которые мы застряли.

0

Что вы хотите заменить (и распечатать) на 0x00 в полученной строке?

Конструктор отвечает за преобразование char [] в строку. Как указывалось другими, вы должны использовать другой конструктор. Код ниже работает для меня, но он не очень робот. Первым параметром должен быть указатель на массив (вы можете использовать безопасное литье), а второй параметр - длина массива (вы можете рассчитать это в более сложном способе ).

#include <iostream> 
int main() { 
    unsigned char cbuffer[]={0x61,0x00,0x62,0x63,0x00}; 
    std::string sbuffer((char *)cbuffer,5); 
    std::cout << sbuffer << std::endl; 
} 
Смежные вопросы