В Интернете есть несколько сообщений, в которых предлагается использовать std::vector<unsigned char>
или что-то подобное для двоичных данных.
Но я предпочел бы вариант std::basic_string
для этого, поскольку он предоставляет множество удобных функций манипуляции с строкой. И AFAIK, так как С++ 11, стандарт гарантирует, что все известные реализации С++ 03 уже сделали: std::basic_string
хранит его содержимое в памяти.
На первый взгляд тогда std::basic_string<unsigned char>
может быть хорошим выбором.
Я не хочу использовать std::basic_string<unsigned char>
, потому что почти все функции операционной системы принимают только char*
, что делает явным приведение. Кроме того, строковые литералы const char*
, поэтому мне потребуется явный приведение к const unsigned char*
каждый раз, когда я назначил строковый литерал для моей двоичной строки, чего я также хотел бы избежать. Кроме того, функции для чтения и записи в файлы или сетевые буферы аналогично принимают указатели char*
и const char*
.
Это оставляет std::string
, что в основном является typedef для std::basic_string<char>
.
Единственная потенциальная оставшаяся проблема (которую я вижу) с использованием std::string
для двоичных данных заключается в том, что std::string
использует char
(который может быть подписан).
char
, signed char
и unsigned char
- три разных типа, а char
может быть либо без знака, либо подписанным.
Итак, когда фактическое значение байта 11111111b
возвращается из std::string:operator[]
как char, и вы хотите проверить его значение, его значение может быть либо 255
(если char
не указано), либо это может быть "что-то отрицательное" (если char
подписано, в зависимости от вашего числа).
Аналогично, если вы хотите явно добавить фактическое значение байта 11111111b
в std::string
, просто добавление (char) (255)
может быть определено реализацией (и даже поднять сигнал), если char
подписан, а int
to char
приводит к переполнению.
Итак, есть ли безопасный способ обойти это, что делает std::string
двоично-безопасным снова?
В § 3.10/15 говорится:
Если программа пытается получить доступ к сохраненному значению объекта через значение gl другого, чем одно из следующих типов, поведение undefined:
- [...]
- тип, который является подписанным или неподписанным типом, соответствующим динамическому типу объекта,
- [...]
- a char или неподписанный char тип.
Что, если я правильно понимаю, похоже, позволяет использовать указатель unsigned char*
для доступа и управления содержимым std::string
и делает это также хорошо определенным. Он просто переинтерпретирует бит-шаблон как unsigned char
без каких-либо изменений или потери информации, а именно потому, что для представления значения должны использоваться все биты в char
, signed char
и unsigned char
.
Затем я мог бы использовать эту интерпретацию std::string
std::string
в качестве средства доступа и изменения значений байтов в диапазоне [0, 255]
в четко и переносимом виде независимо от подписанности char
.
Это должно решить любые проблемы, связанные с потенциально подписанным char
.
Правильны ли мои предположения и выводы?
Кроме того, интерпретация unsigned char*
одного и того же шаблона бита (т.е. 11111111b
или 10101010b
) гарантирована одинаково для всех реализаций? Иначе говоря, стандартная ли гарантия гласит, что "просматривая глаза unsigned char
", один и тот же шаблон бит всегда приводит к одному и тому же числовому значению (если число бит в байте одинаковое)?
Можете ли я безопасно (т.е. без каких-либо undefined или определенных реализацией) использовать std::string
для хранения и обработки двоичных данных в С++ 11?