2016-04-21 4 views
1

Я пытаюсь выбрать биты [0: 2] и биты [6: 8] битовой строки 1010000000001. Биты [0: 2] равны 001, а биты [6: 8] - 000. Я попытался выбрать эти биты с:Выбор бит в C

int instr = 0x1401; 
int src2 = (instr & 0x0006); //get bits [2:0] 
int src1 = (instr & 0x01C0) >> 6; //get bits [6:8] 

printf("%04x, %04x",src2, src1); 

Однако я получаю, что SRC1 и src2 оба 0000. может кто-то пожалуйста, помогите мне понять, что я делаю неправильно, поэтому я могу выбрать биты [0: 2] и [ 6: 8]?

+0

Я пытаюсь выбрать бит [0: 2] и [6: 8] – foobar5512

+1

1 + 2 + 4 = 7. Поэтому используйте '0x7', чтобы получить три младших значащих бита, а не' 0x6'. –

+0

Бит 0 имеет значение 1, а не 0, поэтому ваша маска 6 равна-1. – kfsone

ответ

5

Посмотрите на этот код:

#include <stdio.h> 

int main (void) { 
    unsigned instr = 0x1401; 
    unsigned src2 = instr & 0x0007;  // 7 in hex == 0000 0000 0111 in binary 
    unsigned src1 = (instr & 0x01C) >> 6; // 1C in hex == 0001 1100 0000 in binary 

    printf("%04x, %04x", src2, src1); 
} 

Она маскирует нужных битов в instr и сдвигает их правильное смещение , Кроме того, при выполнении манипуляции с битами предпочтительными являются неподписанные типы.

0

Из того, что я вижу, если вы получаете результат от 0x1401 & 0x0006, вы получаете 0 и получаете то же самое от 0x1401 & 0x01c0. Бит сдвига вы делаете на SRC1 только 0 сдвиг вправо 6 бит, которые по-прежнему 0.

+0

А, ок. Итак, как мне получить первые три бита 001? – foobar5512

+1

Для бит [0: 3], который будет 0x000f, для [0: 2], который будет 0x0007, для [6: 8], который будет 0x01c0 – rfisher

1

Это проще просто написать функцию для вычисления любого произвольного битного среза (здесь используя 1, а не 0 как наименее значащий бит):

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

int bit_select(int num, size_t start, size_t end) 
{ 
    assert(end >= start); 

    const int mask = (1 << (end-start+1)) - 1; 
    const int shift = start - 1; 

    return (num & (mask << shift)) >> shift; 
} 

int main(void) 
{ 
    printf("Bits 1...3 of 01100101: %d\n", bit_select(0x65, 1, 3)); 
    printf("Bits 3...3 of 01100101: %d\n", bit_select(0x65, 3, 3)); 
    printf("Bits 4...4 of 01100101: %d\n", bit_select(0x65, 4, 4)); 
    printf("Bits 3...7 of 01100101: %d\n", bit_select(0x65, 3, 7)); 

    return 0; 
} 

с выходом:

[email protected]:~/src/sandbox$ ./bitselect 
Bits 1...3 of 01100101: 5 
Bits 3...3 of 01100101: 1 
Bits 4...4 of 01100101: 0 
Bits 3...7 of 01100101: 25 
[email protected]:~/src/sandbox$ 
+0

Использование 'assert()' и 'pow()' кажется чтобы сделать его несколько неэффективным. –

+0

Эффективность 'assert()' не имеет значения, так как это не-op в выпуске. Использование 'pow()' более эффективно, чем вручную вычислять, выписывать и отлаживать тысячи индивидуально заданных масок, а затем писать вопрос о переполнении стека о проблемах, с которыми вы сталкиваетесь. –

+0

Почему бы не использовать 'mask = (1 << (end-start + 1)) - 1' вместо' pow() '? И почему бы не просто вернуть '(num >> shift) & mask'? Но тогда это для образовательных целей, а не для использования в производстве, поэтому кто заботится об эффективности. – ndim

0

Потому что вы при условии неправильной маски.

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

unsigned src2 = instr & 0b111; 
0
int instr = 0x1401; 
//results in instr containing (ignoring endian) 
//0x00001401 
//or in binary 
//0b0000 0000 0000 0000 0001 0100 0000 0001 

//extracting bits 2:0 is normally done by: 
int src2 = instr & 0x00000007; 

//extracting bits 8:6 is normally done by: 
int src1 = (instr & 0x000001C0) >> 6; 

//note that if bit 31 is to be extracted, 
//the bit shifting will not work 
//due to sign propagation of a negative number