Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Чтение символов на битовом уровне

Автор вопроса: Jamie KeelingОтветов: 3

Я хотел бы иметь возможность вводить символ с клавиатуры и отображать двоичный код для указанного ключа, например, в формате 00000001.

Кроме того, я также хотел бы прочитать биты таким образом, чтобы я мог вывести, являются ли они истинными или ложными.

e.g.

01010101 = false,true,false,true,false,true,false,true

Я бы опубликовал идею того, как я пытался сделать это сам, но я понятия не имею, я все еще экспериментирую с C, и это мой первый опыт программирования на таком низком уровне.

Спасибо

  • Вы хотите это на C или на C#? Тег .net3-5, который вы поместили, будет означать C#, но вы также поместите тег C, который несовместим. Marcel Gosselin 02.02.2010
  • Это было веселое упражнение! Aiden Bell 02.02.2010

cbinarybit-manipulation

Ответы

Ответ 1 · рейтинг 3 · Steve Jessop

Этот код C89:

/* we need this to use exit */
#include <stdlib.h>
/* we need this to use CHAR_BIT */
#include <limits.h>
/* we need this to use fgetc and printf */
#include <stdio.h>

int main() {
    /* Declare everything we need */
    int input, index;
    unsigned int mask;
    char inputchar;

    /* an array to store integers telling us the values of the individual bits.
       There are (almost) always 8 bits in a char, but it doesn't hurt to get into
       good habits early, and in C, the sizes of the basic types are different
       on different platforms. CHAR_BIT tells us the number of bits in a byte.
     */
    int bits[CHAR_BIT];

    /* the simplest way to read a single character is fgetc, but note that
       the user will probably have to press "return", since input is generally
       buffered */
    input = fgetc(stdin);
    printf("%d\n", input);

    /* Check for errors. In C, we must always check for errors */
    if (input == EOF) {
        printf("No character read\n");
        exit(1);
    }

    /* convert the value read from type int to type char. Not strictly needed,
       we can examine the bits of an int or a char, but here's how it's done.
     */
    inputchar = input;

    /* the most common way to examine individual bits in a value is to use a
       "mask" - in this case we have just 1 bit set, the most significant bit
       of a char. */
    mask = 1 << (CHAR_BIT - 1);

    /* this is a loop, index takes each value from 0 to CHAR_BIT-1 in turn,
       and we will read the bits from most significant to least significant. */
    for (index = 0; index < CHAR_BIT; ++index) {
        /* the bitwise-and operator & is how we use the mask.
           "inputchar & mask" will be 0 if the bit corresponding to the mask
           is 0, and non-zero if the bit is 1. ?: is the ternary conditional
           operator, and in C when you use an integer value in a boolean context,
           non-zero values are true. So we're converting any non-zero value to 1.
         */
        bits[index] = (inputchar & mask) ? 1 : 0;

        /* output what we've done */
        printf("index %d, value %u\n", index, inputchar & mask);

        /* we need a new mask for the next bit */
        mask = mask >> 1;
    }

    /* output each bit as 0 or 1 */
    for (index = 0; index < CHAR_BIT; ++index) {
        printf("%d", bits[index]);
    }
    printf("\n");

    /* output each bit as "true" or "false" */
    for (index = 0; index < CHAR_BIT; ++index) {
        printf(bits[index] ? "true" : "false");
        /* fiddly part - we want a comma between each bit, but not at the end */
        if (index != CHAR_BIT - 1) printf(",");
    }
    printf("\n");
    return 0;
}

Вам не обязательно нужны три цикла - вы можете объединить их вместе, если хотите, и если вы делаете только один из двух видов вывода, вам не нужен массив, вы можете просто использовать каждое значение бита как вы маскируете это. Но я думаю, что это разделяет вещи и, надеюсь, их легче понять.

Ответ 2 · рейтинг 4 · Thomas Pornin

Для настройки битов часто безопаснее использовать типы без знака, потому что сдвиги отрицательных значений со знаком имеют эффект, зависящий от реализации. Обычный char может быть как подписанным, так и неподписанным (традиционно он не подписан на платформах MacIntosh, но подписан на ПК). Следовательно, сначала приведите своего персонажа к типу unsigned char.

Тогда вашими друзьями будут побитовые логические операторы (&, |, ^ и ~) и операторы сдвига (<< и >>). Например, если ваш персонаж находится в переменной x, то для получения 5-го бита вы просто используете: ((x >> 5) & 1). Операторы сдвига перемещают значение вправо, отбрасывая пять младших битов и перемещая интересующий вас бит в "самое нижнее положение" (он же "крайний правый"). Побитовое И с 1 просто устанавливает все остальные биты в 0, поэтому результирующее значение равно 0 или 1, что является вашим битом. Обратите внимание, что я нумерую биты от левого значащего (самого правого) до самого значащего (крайнего левого) и начинаю с нуля, а не с единицы.

Если вы предполагаете, что ваши символы 8-битные, вы можете написать свой код как:

unsigned char x = (unsigned char)your_character;
int i;

for (i = 7; i >= 0; i --) {
    if (i != 7)
        printf(",");
    printf("%s", ((x >> i) & 1) ? "true" : "false");
}

Вы можете заметить, что, поскольку я нумерую биты справа налево, а вы хотите выводить слева направо, индекс цикла должен уменьшаться.

Обратите внимание, что в соответствии со стандартом C unsigned char имеет по крайней мере восемь бит, но может иметь и больше (в настоящее время только несколько встроенных DSP имеют символы, которые не являются 8-битными). Для дополнительной безопасности добавьте это в начало кода (как объявление верхнего уровня):

#include <limits.h>
#if CHAR_BIT != 8
#error I need 8-bit bytes!
#endif

Это предотвратит успешную компиляцию, если целевая система окажется одним из этих специальных встроенных DSP. Как примечание к примечанию, термин "байт" в стандарте C означает "элементарную единицу памяти, которая соответствует unsigned char", так что, на языке C, байт может иметь более восьми битов (байт не является всегда октет). Это традиционный источник путаницы.

Ответ 3 · рейтинг 4 · Antony Woods

Это, вероятно, не самый безопасный способ - никаких проверок работоспособности/размера/типа - но он все равно должен работать.

unsigned char myBools[8];
char myChar;

// get your character - this is not safe and you should
// use a better method to obtain input...
// cin >> myChar; <- C++
scanf("%c", &myChar);

// binary AND against each bit in the char and then
// cast the result. anything > 0 should resolve to 'true'
// and == 0 to 'false', but you could add a '> 1' check to be sure.
for(int i = 0; i < 8; ++i)
{
   myBools[i] = ( (myChar & (1 << i) > 0) ? 1 : 0 );
}

Это даст вам массив беззнаковых символов - либо 0, либо 1 (истина или ложь) - для символа.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы