Что происходит внутри цикла в binary_array_to_numbers(). Я знаю, что он делает, но я не понимаю, как он это делает. Впервые вижу использование << и |. Заранее спасибо.
unsigned binary_array_to_numbers(const unsigned *bits, size_t count) {
unsigned res = 0;
for (size_t i = 0; i < count; i++)
res = res << 1 | bits[i];
return res;
}
int main(void) {
unsigned bits[] = {0, 0, 1, 0};
unsigned received = binary_array_to_numbers(bits, sizeof(bits) / sizeof(bits[0]));
return 0;
}



Оператор сдвига влево res << 1 сдвигает разрешение на 1 бит, поэтому самый правый бит теперь равен нулю. Затем вы применяете побитовый оператор или |, чтобы установить этот самый правый бит в значение bits[i] (предполагается, что bits является массивом 0 или 1 и хранится с прямым порядком байтов, иначе ваш алгоритм не будет работать).
Скажем bits = { 1, 0, 1 } (т.е. 5; в вашем примере это интереснее, чем 2). Вот что происходит на каждой итерации:
0.
res = res << 1 | bits[0]
res = 0x0 << 1 | 1
res = 1
res = 1 << 1 | bits[1]
res = 0x2 | 0
res = 0x2
res = 0x2 << 1 | bits[2]
res = 0x4 | 1
res = 0x5
Оператор сдвига влево сдвигает все биты влево на определенное количество заданных битов. Битовые позиции, освобожденные оператором сдвига влево, заполняются 0. Символом оператора сдвига влево является <<.
Результат побитового ИЛИ равен 1, если хотя бы один соответствующий бит двух операндов равен 1. В C побитовый оператор ИЛИ обозначается |.
sizeof(bits) / sizeof(bits[0]) — это распространенный метод, когда вы хотите вычислить количество элементов массива фиксированного размера во время компиляции. В этом случае компилятор молча заменит все выражение на 4.
Результирующий целочисленный тип операции sizeof является типом size_t, который представляет собой большое целое число без знака, подходящее для описания размеров массивов и т. д. Поэтому этот тип используется в качестве параметра функции.
Массив передается функции как const unsigned *, что означает, что он доступен только для чтения и не будет изменен функцией. Это хорошая практика, и она называется константная корректность.
res в функции формирует бинарное битовое поле.
Приоритет оператора в выражении res = res << 1 | bits[i]; дает [] больше << больше | больше =. То есть это эквивалентно:
res = ( (res << 1) | bits[i] );
res << 1 сдвигает предыдущий сохраненный результат на один бит влево. В первый раз цикла это все нули. Когда значение сдвигается, в младшем значащем бите (LSB) появляется ноль.
Побитовое ИЛИ | выполняется между всем, что хранится в res, тем, что хранится в bits[i], что в данном случае бывает либо 0, либо 1, хранящимся в младшем бите bits[i].
Поскольку остальная часть bits[i] равна нулю, только эти данные LSB имеют значение для OR. А в случае res мы знаем, что его младший бит равен нулю. Таким образом, в этом конкретном случае это то же самое, что переместить содержимое bits[i] в младший бит res, не затрагивая другие биты, уже сохраненные в res.
Результатом будет двоичное битовое поле со значением 0010 или, если вы будете использовать шестнадцатеричное значение 0x2.
Что вы имеете в виду под «десятичным»?