В Интернете есть несколько сообщений, в которых предлагается использовать 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?