попробуй объяснить с моим грубым английским: (
Мой код (предположим, что все входные данные корректны. Избегайте защитного программирования)
#include <stdio.h>
enum { SZ = 11 };
unsigned int htoi(const char *s);
int main()
{
char buff[SZ]; //Max 11 char: 0x XX XX XX XX '\0' (2 + 8 + 1)
while(fscanf(stdin, "%s", buff) != EOF)
printf("%X\n", htoi(buff) );
return 0;
}
unsigned int htoi(const char *s)
{
unsigned int i, r = 0;
for(i = (s[1] == 'x') ? 2 : 0; s[i] != '\0'; i++)
r = ( r << 4 ) + ( (s[i] > '9') ? 0x9 : 0x0 ) + ( s[i] & 0xF );
return r;
}
Хорошо, прежде всего, присвойте r = 0.
Затем, когда мы запускаем for-bucle, мы передаем значение init индексной переменной i. Мы должны проверить, имеет ли строка формат 0x или нет. Нам нужно только проверить позицию 1, чтобы узнать, обрабатываем ли мы входную строку в формате 0x или без него.
Теперь у нас есть индекс, указывающий на первый правильный символ! Для каждой итерации мы смещаем 4 бита влево. Мы получаем 4 нуля. Идеальный пробел, чтобы добавить новую шестнадцатеричную цифру! Пример:
Input: 0xBE1234
Is s[1] == 'x' ? true then i = 2;
r = 0;
iter 1: r = 0x0; r = 0x0; r = 0xB;
iter 2: r = 0xB; r = 0xB0; r = 0xBE;
iter 3: r = 0xBE; r = 0xBE0; r = 0xBE1;
iter 4: r = 0xBE1; r = 0xBE10; r = 0xBE12;
iter 5: r = 0xBE12; r = 0xBE120; r = 0xBE123;
iter 6: r = 0xBE123; r = 0xBE1230; r = 0xBE1234
Может быть, это немного сложнее:
r = ( r << 4 ) + ( (s[i] > '9') ? 0x9 : 0x0 ) + ( s[i] & 0xF );
Прежде всего, мы смещаем 4 бита, так же, как умножение на 16, но более эффективно. Затем мы смотрим, если у нас есть символ ASCII больше, чем «9». Если это правда, мы работаем с A, B, C, D, E, F или a, b, c, d, e, f. Помните, мы предполагаем, что у нас есть правильный ввод.
Хорошо, теперь взглянем на таблицу ASCII:
A = 0100 0001 - a = 0110 0001
...
F = 0100 0110 - f = 0110 0110
но мы хотим что-то вроде этого:
A = 0000 1010 - a = 0000 1010
...
F = 0000 1111 - f = 0000 1111
Как мы это делаем? После смещения очищаем 4 старших бита с маской s [i] & 0xF:
s[2] == 'B' == 0100 0010
s[2] & 0xF == 0000 0010
и добавить 9 для адаптации к целочисленному значению (только в том случае, если s [i] в {'A' ... 'F', 'a' ... 'f'})
s[2] & 0xF + 0x9 = 0000 0010 + 0000 1001 = 0000 1011 (0xB)
Наконец, мы добавляем к смещенному значению r и присваиваем значение r. Последовательность выполнения для второй итерации (с [3]):
r == 0xB, s[3] == 'E' == 0100 0101 (start iter 2)
(r << 4) == 0xB0, s[3] == 'E' == 0100 0101 (displacement r << 4 )
(r << 4) == 0xB0, (s[3] & 0xF + 0x9) == 0000 1110 == 0xE (clear most significant bits of s[3] and add 0x9)
r = (r << 4) + ( s[3] & 0xF + 0x9 ) == 0xBE == 1011 1110 (add all and assign to r)
Что произойдет, если у нас будет такой числовой символ, как s [4]?
s[4] == '1' == 0011 0001
s[4] & 0xF == 0000 0001
Смещение r на четыре позиции, добавление 0 (ничего), добавление результата логической операции s [i] & 0xF и, наконец, присвоение r.
r == 0xBE, s[4] == '1' == 0011 0001 (start iter 3)
(r << 4) == 0xBE0, s[4] == '1' == 0011 0001 (displacement r << 4 )
(r << 4) == 0xBE0, (s[4] & 0xF + 0x0) == 0000 0001 (clear most significant bits of s[4] and add 0)
r = (r << 4) + s[4] & 0xF == 0xBE1 == 1011 1110 0001 (add all and assign)
Помните, мы сдвигаем 4, чтобы не разбивать биты цифр, потому что мы добавляем менее значимые биты с пропуском в четыре нуля.
PD: Я обещаю улучшить мой английский для объяснения лучше, извините.