2011-12-21 3 views
9

У меня есть шестнадцатеричное число 0x37, а его двоичное представление 0011 0111. Как мне получить доступ к первым двум битам двоичного представления, которое равно «11»? Как использовать бит-сдвиг или маскирование для достижения этого? Я могу получить доступ к бит за битом, но не два бита за один раз?Доступ к битам в char в C

ответ

12

Если у вас & ваш номер с 0x03, вы получите последние два бита.

char c = 0x37; 
char mask = 0x03; 
char lastTwo = c & mask; 
2

Ваш лучший выбор - использовать битовую маскировку, как вы уже упоминали. Что-то вроде этого следует сделать трюк:

x = 0x37; 
y = x&0x30; //Mask out the first two bits of the higher nibble 
y = y>>4; 
+0

Здесь я предполагал, что вы хотите изолировать 11 от «0011». Если вам нужны только два младших бита, x & 0x03 будет работать, как показал dasblinkenlight. – zje

9

Вот пример, чтобы получить доступ к его по кусочкам:

#include <stdio.h> 
int main() 
{ 
    char byte = 0x37; 
    int i; 

    for(i = 7; 0 <= i; i --) 
     printf("%d\n", (byte >> i) & 0x01); 

    return 0; 
} 
5

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

Вот пример, написанный на компьютере Ubuntu Linux и протестированный с помощью GCC.

#include <assert.h> 
#include <stdio.h> 

#pragma pack(1) 
typedef struct 
{ 
    unsigned int low2: 2; // 2 bits of the byte 
    unsigned int high6: 6; // 6 more bits of the byte 
} MYBYTE; 

typedef union 
{ 
    MYBYTE mybyte; 
    unsigned char b; 
} MYUNION; 

main() 
{ 
    MYUNION m; 

    assert(sizeof(m) == 1); 
    m.b = 0x03; 
    assert(m.mybyte.low2 == 0x03); 
    assert(m.mybyte.high6 == 0x00); 

    printf("low2 of 0x03 is: %u\n", m.mybyte.low2); 
    printf("high6 of 0x03 is: %u\n", m.mybyte.high6); 

    m.b = 0xff; 

    printf("low2 of 0x03 is: %u\n", m.mybyte.low2); 
    printf("high6 of 0x03 is: %u\n", m.mybyte.high6); 
    assert(m.mybyte.low2 == 0x03); 
    assert(m.mybyte.high6 == 0x3f); 

    m.mybyte.high6 = 0x1c; 
    m.mybyte.low2 = 0x01; 
    assert(m.b == 0x71); 
    printf("m.b is: 0x%02x\n", m.b); 

    return 0; 
} 

Объединение существует, поэтому мы можем получить к нему доступ в виде полного байта или получить доступ к нему по битовым полям. #pragma pack(1), чтобы убедиться, что битовые поля упали до байта, без лишних бит «заполнения». (Как я уже говорил, вы полагаетесь на детали реализации, когда используете битовые поля.)

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

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

Если вы не собираетесь использовать бит-поля, я предлагаю вам определить функцию, которая выполняет ваши смены и маскировку, чтобы вы не испортили. Может быть, что-то вроде этого:

#include <limits.h> 


static unsigned int _bit_masks[] = 
{ 
    0x00000000, 0x00000001, 0x00000003, 0x00000007, 
    0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 
    0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 
    0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 
    0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 
    0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, 
    0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, 
    0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, 
}; 


#define MIN(a, b) \ 
    ((a) < (b) ? (a) : (b)) 

unsigned int 
bits(unsigned int x, unsigned int i_bit, unsigned int c_bits) 
{ 
    assert(UINT_MAX >= 4294967295U); // unsigned int must be at least 32-bit 
    assert(i_bit <= 31); 
    if (i_bit > 31) 
     return 0; 
    c_bits = MIN(c_bits, 32 - i_bit); 

    // shift-and-mask to grab the requested bits, and return those bits 
    return (x >> i_bit) & _bit_masks[c_bits]; 
} 

Вы передаете в значении, то какое бита позицию, которую вы хотите биты от, и сколько бита вы хотите. Таким образом, чтобы захватить 6 бит, начиная с битовой позиции 2, с тестовым значением 0x71 можно назвать:

x = bits(0x71, 2, 6); // x is set to 0x1c 

Если вам не нравится, таблицы поиска, и вы хотите, мельчайший код, чтобы сделать это, вам можно использовать:

unsigned int 
bits(unsigned int x, unsigned int i_bit, unsigned int c_bits) 
{ 
    const unsigned int mask_bits = 0xffffffff; 

    assert(UINT_MAX >= 4294967295U); // unsigned int must be at least 32-bit 
    assert(i_bit <= 31); 
    if (i_bit > 31) 
     return 0; 
    c_bits = MIN(c_bits, 32 - i_bit); 

    // shift-and-mask to grab the requested bits, and return those bits 
    return (x >> i_bit) & (mask_bits >> (32 - c_bits)); 
} 

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

Если вы объявите эту последнюю версию функции как встроенную, поместите ее в заголовочные файлы и вызовите ее с постоянными значениями для i_bit и c_bits, она скомпилирует до минимального кода для решения проблемы. (Например, если i_bit равно 0, компилятор знает, что >> 0 ничего не делает и просто не сгенерирует этот код. И если компилятор знает c_bits как константу, он может выполнять всю работу смены mask_bits во время компиляции.) Но вам нужно убедиться, что вы используете версию assert(), которая не компилируется в вашей сборке релизов, а также использует собственный макрос ASSERT() и не скомбинирует макрос.

2

Это самый простой функции использовать, я не хочу, чтобы другие бороться в течение длительного времени, прежде чем получить что-то похожее на это -

char get_bits(char a, char no_of_bits) 
{ 
    return a & ((no_of_bits << 1) - 1); 
} 
char a = 0x37; 
char b = get_bits(a, 2); 

Надежда это помогает кому-то в будущем

Смежные вопросы