Классическая уловка из 8-битного микро в эпоху ассемблера заключается в том, чтобы разбить преобразование ниббла на два сегмента. Значение от 0 до 9 и значение от 10 до 15. Затем простая арифметика сохраняет 16-байтовую таблицу поиска.
void SendDigit(int c) {
c &= 0x0f;
c += (c <= 9) ? '0' : 'A'-10;
SendU(c);
}
void SendArray(const unsigned char *msg, size_t len) {
while (len--) {
unsigned char c = *msg++;
SendDigit(c>>4);
SendDigit(c);
}
}
Пара дополнительных примечаний в порядке. Во-первых, это работает, потому что цифры и буквы в ASCII находятся в непрерывном диапазоне. Если вам не повезло хотеть EBCDIC , это все равно работает, так как буквы от 'A' до 'F' также являются смежными (но остальная часть алфавита разбита на три пролета).
Во-вторых, я изменил подпись SendArray()
. Моя версия старается сделать буфер без знака, что обычно безопаснее при планировании преобразования байтов в какой-то больший целочисленный тип для выполнения арифметики. Если они подписаны, то такой код, как nibble[(*msg)>>4]
, может попытаться использовать отрицательный индекс в массиве, и результат будет бесполезен.
Наконец, я добавил параметр длины. Для общего двоичного дампа у вас, вероятно, нет байтового значения, которое имеет смысл использовать в качестве конечного сторожа. Для этого счет намного эффективнее.
Редактировать: Исправлена ошибка: для цифр свыше 10 арифметика равна c + 'A' - 10
, а не c + 'A'
. Спасибо Бруксу Моисею за то, что он это понял.