12

I am interested in writing a function getMyByteChunkFunction that accepts two parameters - a 32-bit integer and a byte offset (0, 1, 2, or 3), then returns the corresponding byte out of the 32-bit integer. For example, given this integer:

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

the function call getMeByteChunkFunction(word, 2) returns 00001001.

However, I am limited in the bitwise operators I can use. I am only allowed to use >>, <<, and exactly one subtraction. I know how to do this using AND and XOR, but I don't know how I'd use a subtraction here. Any ideas?

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
David
  • 175
  • 1
  • 4
  • 8
  • Tagged as homework (had to drop "logic" because max 5 tags.) – Jonathan Grynspan Sep 02 '11 at 00:01
  • @JBentley: I made that comment two years ago. – Jonathan Grynspan Apr 25 '13 at 03:01
  • [Get nth byte of integer](https://stackoverflow.com/q/32695714/995714), [How to get the value of individual bytes of a variable?](https://stackoverflow.com/q/8680220/995714), [Get single byte from int](https://stackoverflow.com/q/19821262/995714) – phuclv Jul 26 '18 at 07:35
  • Possible duplicate of [c get nth byte of integer](https://stackoverflow.com/questions/7787423/c-get-nth-byte-of-integer) – phuclv Jul 26 '18 at 07:35

6 Answers6

25

One idea is as follows. Suppose that you have a four-byte value like this one:

aaaaaaaa bbbbbbbb cccccccc dddddddd

Let's suppose that you want to get the byte bbbbbbbb out of this. If you shift right by two bytes, you get

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

This value is equal to what you want, except that at the top it has ???????? ???????? aaaaaaaa (because we're not sure if the shift is sign-preserving or not, since I don't know if your value is unsigned or not.) No worries, though; we can get rid of these unknown values and the a byte. To get rid of the top, suppose that you shift right another byte, giving

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

Now, shift left one byte to get

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

If you then do this subtraction, you get

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

And voilà... you've got the value you want!

I'll leave the actual code as an exercise to the reader. Don't worry; it's not particularly hard. :-)

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
6

You can do it just with shifting. Shift left to get rid of the bits on the left, then shift right to get rid of the bits on the right and move the wanted byte into the least significant spot.

Tom Zych
  • 13,329
  • 9
  • 36
  • 53
2

The following code should also answer the question.

#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;
}

The output is

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

The concept can be explained based on templatetypedef's explanation and expanded as follows.

(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)
----------------
oon
  • 61
  • 3
2
result = (word >> (n_byte << 3)) & 0xFF;
neurocore
  • 29
  • 1
  • 2
1

There's a very clever trick for this, which I use for converting objects into char strings (to transmit as a stream):

//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

In short, the above treats source as 4 separate chars (which are normally only 1 byte in size), and the pointer allows you to treat it as a memory section. You dereference it before return.

Use it whatever purpose (even commercial).

Compressed format?

#define GetByte(X,Y) (*(((unsigned char *)&X)+Y))
SE Does Not Like Dissent
  • 1,767
  • 3
  • 16
  • 36
0

here is the code:

#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;
}

and the output:

aa09ca05
09
Michał Šrajer
  • 30,364
  • 7
  • 62
  • 85
  • ANSI/ISO C specification says that long must me at least 4 bytes. Do you know any ANSI compatible C compiler on which it will not work? – Michał Šrajer Sep 02 '11 at 00:21
  • 3
    http://meta.stackexchange.com/questions/10811/how-to-ask-and-answer-homework-questions – Tom Zych Sep 02 '11 at 00:33
  • This answer doesn't explain why the code works - can you go into detail about it? What if you wanted something other than the second byte? Why are you using `unsigned long` when the input value is an `int`? – templatetypedef Sep 02 '11 at 00:36
  • @templatetypedef: The answers to most of these questions can be found in my answer; this answer implements the same idea. – Tom Zych Sep 02 '11 at 00:41
  • @Michał Šrajer ISO C doesn't specify which kind of shift is used, so you could easily get an arithmetic shift. Now one can easily just use an unsigned type and hope that every compiler ever follows the usual conventions, but that's hardly the best answer (and especially using an unsigned value without mentioning its importance). – Voo Sep 02 '11 at 14:35