Побитовый оператор для получения байта из 32 бит - PullRequest
12 голосов
/ 02 сентября 2011

Я заинтересован в написании функции getMyByteChunkFunction, которая принимает два параметра - 32-разрядное целое и смещение байта (0, 1, 2 или 3), а затем возвращает соответствующий байт из 32-разрядного целого , Например, учитывая это целое число:

            (3)         (2)      (1)      (0)   ---byte numbers
int word = 10101010 00001001 11001010 00000101

вызов функции getMeByteChunkFunction(word, 2) возвращает 00001001.

Однако я ограничен в битовых операторах, которые я могу использовать. Мне разрешено использовать только >>, << и только одно вычитание . Я знаю, как это сделать, используя AND и XOR, но я не знаю, как бы использовать здесь вычитание. Есть идеи?

Ответы [ 6 ]

25 голосов
/ 02 сентября 2011

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

aaaaaaaa bbbbbbbb cccccccc dddddddd

Предположим, что вы хотите получить из этого байт bbbbbbbb.Если вы сдвинете вправо на два байта, вы получите

???????? ???????? aaaaaaaa bbbbbbbb

Это значение равно тому, что вы хотите, за исключением того, что в верхней части оно имеет ???????? ???????? aaaaaaaa (потому что мы не уверены, является ли сдвиг знаком-сохранять или нет, так как я не знаю, является ли ваша ценность без знака или нет.) Однако не стоит беспокоиться;мы можем избавиться от этих неизвестных значений и байта a.Чтобы избавиться от вершины, предположим, что вы сдвигаете вправо еще один байт, давая

???????? ???????? ???????? aaaaaaaa

Теперь сдвиньте влево один байт, чтобы получить

???????? ???????? aaaaaaaa 00000000

Если вы затем выполните это вычитание, выget

    ???????? ???????? aaaaaaaa bbbbbbbb
-   ???????? ???????? aaaaaaaa 00000000
---------------------------------------
    00000000 00000000 00000000 bbbbbbbb

И вуаля ... вы получили желаемое значение!

Я оставлю реальный код в качестве упражнения для читателя.Не волнуйся;это не особенно сложно.: -)

6 голосов
/ 02 сентября 2011

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

2 голосов
/ 01 августа 2014
result = (word >> (n_byte << 3)) & 0xFF;
2 голосов
/ 19 апреля 2013

Следующий код также должен ответить на вопрос.

#include <stdio.h>

int getByte(int x, int n);

void main()
{
    int x = 0xAABBCCDD;
    int n;

    for (n=0; n<=3; n++) {
        printf("byte %d of 0x%X is 0x%X\n",n,x,getByte(x,n));
    }

}

// extract byte n from word x
// bytes numbered from 0 (LSByte) to 3 (MSByte)
int getByte(int x, int n)
{
    return (x >> (n << 3)) & 0xFF;
}

Выход

byte 0 of 0xAABBCCDD is 0xDD
byte 1 of 0xAABBCCDD is 0xCC
byte 2 of 0xAABBCCDD is 0xBB
byte 3 of 0xAABBCCDD is 0xAA

Концепция может быть объяснена на основе templatetypedef и расширена следующим образом.

(3)      (2)      (1)      (0)
aaaaaaaa bbbbbbbb cccccccc dddddddd

{(3),(2),(1),(0)} --> {(3)}
  ???????? ???????? ???????? aaaaaaaa // x>>(3*8) where 3 == n
& 00000000 00000000 00000000 11111111 // 0xFF
  -----------------------------------
  00000000 00000000 00000000 aaaaaaaa // (x >> (8 * n)) & 0xFF

{(3),(2),(1),(0)} --> {(2)}
  ???????? ???????? aaaaaaaa bbbbbbbb // x>>(2*8) where 2 == n
& 00000000 00000000 00000000 11111111 // 0xFF  
  -----------------------------------
  00000000 00000000 00000000 bbbbbbbb

{(3),(2),(1),(0)} --> {(1)}
  ???????? aaaaaaaa bbbbbbbb cccccccc // x>>(1*8) where 1 == n
& 00000000 00000000 00000000 11111111 // 0xFF  
  -----------------------------------
  00000000 00000000 00000000 cccccccc

{(3),(2),(1),(0)} --> {(0)}
  aaaaaaaa bbbbbbbb cccccccc dddddddd // x>>(0*8) where 0 == n
& 00000000 00000000 00000000 11111111 // 0xFF  
  -----------------------------------
  00000000 00000000 00000000 dddddddd

Note (x >> (8 * n)) & 0xFF is equivalent to (x >> (n << 3)) & 0xFF.

64 32 16 8 4 2 1 
----------------
0  0  0  0 0 1 1 // (n==3)
0  0  1  1 0 0 0 // (n*8==n<<3==24)
----------------
0  0  0  0 0 1 0 // (n==2)
0  0  1  0 0 0 0 // (n*8==n<<3==16)
----------------
0  0  0  0 0 0 1 // (n==1)
0  0  0  1 0 0 0 // (n*8==n<<3==8)
----------------
1 голос
/ 02 сентября 2011

Для этого есть очень хитрый трюк, который я использую для преобразования объектов в строки символов (для передачи в виде потока):

//WhichByte should really be an enum to avoid issues
//Counts as 0, 1, 2 or 3
//Modify as unsigned or signed char (for return type and pointer type) as needed
#define BYTE_TYPE unsigned char
BYTE_TYPE GetByte(const unsigned int Source, const unsigned char WhichByte)
{
    if(WhichByte < 0){return 0;}
    if(WhichByte >= sizeof(Source)){return 0;}

    //Converts source into the appropriate pointer
    BYTE_TYPE * C_Ptr = (BYTE_TYPE *)&Source;
    return *(C_Ptr+WhichByte);
}
#undef BYTE_TYPE

Короче говоря, приведенное выше обрабатывает источник как 4 отдельных символа (которыеобычно имеют размер только 1 байт), и указатель позволяет рассматривать его как раздел памяти.Вы разыменовываете его перед возвратом.

Используйте его для любых целей (даже коммерческих).

Сжатый формат?

#define GetByte(X,Y) (*(((unsigned char *)&X)+Y))
0 голосов
/ 02 сентября 2011

вот код:

#include <stdio.h>

int main() {
    unsigned long n = 0xAA09CA05L; /* 10101010 00001001 11001010 00000101 */
    printf("%08lx\n", n); /* input */
    printf("%02lx\n", ((n<<8)>>24)); /* output */
    return 0;
}

и вывод:

aa09ca05
09
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...