unsigned char в массив беззнаковых символов из 8 исходных бит

Я пытаюсь взять данный беззнаковый символ и сохранить 8-битное значение в массиве беззнаковых символов размера 8 (1 bit per array index).

Итак, учитывая беззнаковый char A

Я хочу создать массив беззнаковых символов, содержащий 0 1 0 0 0 0 0 1 (одно число на индекс)

Какой способ добиться этого был бы наиболее эффективным? С Днем Благодарения, кстати !!


person David Baez    schedule 27.11.2014    source источник
comment
используйте ch & (1 << n), чтобы выбрать бит, а затем соответственно установите значения в вашем массиве   -  person M.M    schedule 27.11.2014
comment
двоичный и (&) и сдвиг бит для победы. Следует опубликовать это как ответ вместо комментария Мэтт.   -  person James H    schedule 27.11.2014


Ответы (3)


Самый быстрый (не уверен, что это то, что вы называете "эффективным") способ сделать это, вероятно, примерно так:

void char2bits1(unsigned char c, unsigned char * bits) {
    int i;
    for(i=sizeof(unsigned char)*8; i; c>>=1) bits[--i] = c&1;
}

Функция принимает символ для преобразования в качестве первого аргумента и заполняет массив bits соответствующим битовым шаблоном. На моем ноутбуке он работает за 2,6 нс. Он предполагает 8-битные байты, но не сколько байтов имеет длина char, и не требует, чтобы входной массив был предварительно инициализирован нулем.

Я не ожидал, что это будет самый быстрый подход. Моя первая попытка выглядела так:

void char2bits2(unsigned char c, unsigned char * bits) {
    for(;c;++bits,c>>=1) *bits = c&1;
}

Я думал, что это будет быстрее, если избежать поиска в массиве, зациклившись в естественном порядке (за счет производства битов в порядке, обратном запрошенному), и остановившись, как только c станет равным нулю (так что массив битов будет должны быть инициализированы нулем перед вызовом функции). Но, к моему удивлению, эта версия имела время работы 5,2 нс, что вдвое больше, чем у версии выше.

Исследование соответствующей сборки показало, что разница заключалась в разворачивании петли, которая выполнялась в первом случае, но не во втором. Это иллюстрация того, как современные компиляторы и современные процессоры часто обладают удивительными характеристиками производительности.

Изменить: если вы действительно хотите, чтобы символы без знака в результате были символами '0' и '1', используйте эту измененную версию:

void char2bits3(unsigned char c, unsigned char * bits) {
    int i;
    for(i=sizeof(unsigned char)*8; i; c>>=1) bits[--i] = '0'+(c&1);
}
person amaurea    schedule 27.11.2014

Вы можете использовать битовые операторы в соответствии с рекомендациями.

#include <stdio.h>

main() {
    unsigned char input_data = 8;
    unsigned char array[8] = {0};
    int idx = sizeof(array) - 1;
    while (input_data > 0) {
        array[idx--] = input_data & 1;
        input_data /= 2; // or input_data >>= 1;
    }

    for (unsigned long i = 0; i < sizeof(array); i++) {
        printf("%d, ", array[i]);
    }
}
person NetVipeC    schedule 27.11.2014
comment
Почему не простой input_data >>= 1? - person amaurea; 27.11.2014
comment
Поскольку давным-давно каждый компилятор будет оптимизировать input_data /= 2;, как вы писали input_data >>= 1;, обычно наиболее очевидна /2 операция сдвига, люди лучше понимают разделение этого сдвига, в этом случае работа с битами, вероятно, не представляет большой проблемы. - person NetVipeC; 27.11.2014
comment
Я не согласен. Что вы делаете по логике, так это сдвигаете бит в следующую позицию, чтобы его можно было прочитать с помощью & 1. Деление на два - это просто запутанный способ записи этого слова. - person amaurea; 27.11.2014
comment
То же самое, в одном случае вы немного сдвигаетесь (иногда между новым программистом на C ++ остается вопрос о том, что происходит со смещенным битом), а в другом делении на 2 (основание двоичных чисел, вы вынимаете последнюю цифру в двоичном представлении). Нет проблем, пишите как хотите. Андрей Александреску дал рекомендацию использовать /2 вместо того, чтобы переходить на конференцию C ++ в Facebook год назад, я думаю. Историческое использование >>= 1 состоит в том, что в сборке есть специальная инструкция для shifting by 1, а старые, старые компиляторы не используются, когда вы пишете /2 - person NetVipeC; 27.11.2014
comment
Я понимаю, что он делает. Я не согласен с вами в том, что является наиболее ясным. Когда то, что вы логически делаете, является делением, используйте деление. Когда то, что вы логически делаете, - это сдвиг битов, используйте операцию сдвига битов. Написав это как разделение, вы скрываете цель операции. Тот факт, что вы читали совет не злоупотреблять битовым сдвигом для деления, не означает, что никогда не следует использовать битовый сдвиг! - person amaurea; 28.11.2014
comment
Сохранить как int? Что ты имеешь в виду? - person NetVipeC; 28.11.2014

Возьмите значение, сдвиньте его вправо и замаскируйте, чтобы оставить только младший бит. Добавьте значение младшего бита к символу «0», чтобы получить «0» или «1», и запишите его в массив:

unsigned char val = 65;
unsigned char valArr[8+1] = {};

for (int loop=0; loop<8; loop++)
    valArr[7-loop] = '0' + ((val>>loop)&1);

printf ("val = %s", valArr);
person Chris    schedule 27.11.2014