Как работать с uint8_t вместо char?

Я хочу понять ситуацию, касающуюся uint8_t против char, переносимости, битовых манипуляций, лучших практик, положения дел и т. Д. Знаете ли вы хорошее чтение по этой теме?

Я хочу сделать байтовый ввод-вывод. Но, конечно, у char есть более сложное и тонкое определение, чем uint8_t; Я полагаю, это было одной из причин введения заголовка stdint.

Однако у меня были проблемы с использованием uint8_t несколько раз. Несколько месяцев назад, однажды, потому что iostreams не определены для uint8_t. Разве нет библиотеки C ++, которая делает действительно хорошо определенный byte-IO, то есть читает и пишет uint8_t? Если нет, я предполагаю, что на это нет спроса. Зачем?

Моя последняя головная боль связана с тем, что этот код не скомпилирован:

uint8_t read(decltype(cin) & s)
{
char c;
s.get(c);
return reinterpret_cast<uint8_t>(c);
}

error: invalid cast from type 'char' to type 'uint8_t {aka unsigned char}'

Почему ошибка? Как заставить это работать?

4

Решение

Общий, переносимый, правильный путь туда и обратно:

  1. требуйте в своем API, чтобы все байтовые значения могли быть выражены максимум 8 битами,
  2. использовать совместимость макета char, signed char а также unsigned char для ввода / вывода и
  3. перерабатывать unsigned char в uint8_t по мере необходимости.

Например:

bool read_one_byte(std::istream & is, uint8_t * out)
{
unsigned char x;    // a "byte" on your system
if (is.get(reinterpret_cast<char *>(&x)))
{
*out = x;
return true;
}
return false;
}

bool write_one_byte(std::ostream & os, uint8_t val)
{
unsigned char x = val;
return os.write(reinterpret_cast<char const *>(&x), 1);
}

Некоторое объяснение: Правило 1 гарантирует, что значения могут быть преобразованы в обоих направлениях между uint8_t а также unsigned char без потери информации. Правило 2 означает, что мы можем использовать операции ввода-вывода iostream на unsigned char переменные, даже если они выражены в терминах chars.

Мы могли бы также использовать is.read(reinterpret_cast<char *>(&x), 1) вместо is.get() для симметрии. (С помощью read как правило, для потоковых потоков, превышающих 1, также требуется использование gcount() по ошибке, но это не относится здесь.)

Как всегда, вы никогда не должны игнорировать возвращаемое значение операций ввода-вывода. Это всегда ошибка в вашей программе.

2

Другие решения

Несколько месяцев назад, однажды, потому что iostreams не определены для uint8_t.

uint8_t в значительной степени просто typedef для unsigned char, На самом деле, я сомневаюсь, что вы могли бы найти машину там, где ее нет.

uint8_t read(decltype(cin) & s)
{
char c;
s.get(c);
return reinterpret_cast<uint8_t>(c);
}

С помощью decltype(cin) вместо std::istream не имеет никакого преимущества, это просто потенциальный источник путаницы.
Актерский состав в return— заявление не обязательно; преобразование char в unsigned char работает неявно.

Несколько месяцев назад, однажды, потому что iostreams не определены для uint8_t.

Они есть. Не для uint8_t сам, но, скорее всего, для типа, который он на самом деле представляет. оператор >> перегружен для unsigned char, Этот код работает:

uint8_t read(istream& s)
{
return s.get();
}

поскольку unsigned char а также char может псевдоним друг друга, вы также можете просто reinterpret_cast любой указатель на char строка в unsigned char* и работать с этим.

Если вы хотите максимально портативный способ, посмотрите ответ Kerreks.

0

По вопросам рекламы [email protected]