Search code examples
cmergebinarybytebyte-shifting

c function to merge bytes in a specific order depended on endianness


I want to be able to merge bytes from two unsigned long parameters, taking exactly half of the bytes, the half that starts with the least significant byte of the second param and the rest of the first param.

For example:

x = 0x89ABCDEF12893456 
y = 0x76543210ABCDEF19
result_merged = 0x89ABCDEFABCDEF19

First, I need to check whether the system that I work on is little endian or big endian. I already wrote a function that checks that, called is_big_endian().

now I know that char char *c = (char*) &y will give me the byte that stored at the largest memory address .

Now, I wanted to use AND(&) bitwise operator to merge x and y bytes, but I could not use it because I can't really know what is the size of the "long", it can be different for 32 or 64 bit systems, so I can't really use a fixed size.

Which means I can't use any bit masking like:

(y & 0x00000000ffffffff) | (x & 0xffffffff00000000);

I'm not allowed to use long long, uint_fast64_t or reinterpret_cast or any other "externals" things.

I was thinking about:

  1. using bytes shifting
  2. using an array to store the bits and run a loop on this array.

So I wrote this code, where I can just use the "sizeof" to find the size of the long and not to care if it's a 32 or 64 bit system.

unsigned long merge(unsigned long x, unsigned long int y)
        {
        char* charX = (char*)&x;
        char* charY = (char*)&y;
        if (is_big_endian == 0){
    // it's a little endian machine
            for (int i=0; i<(sizeof(unsigned long))/2; i++){
                *charX<<1;
                *charY>>1;
            }
        }
        else
                {
                    for (int i=0; i<(sizeof(unsigned long))/2; i++){
                    *charX>>1;
                    *charY<<1;
                }
            }
            return (x | y);
        }

I have shitfted the right side of the bits of y if that's a little endian system because the LSB there is the furthest to the left bit. And did the opposite if this is a big endian system.

But it's not working so well and the output is: 0xffffffffbbcdff5f

any help would be appreciated.


Solution

  • The endianness is not relevant, and you can do it like this.

    unsigned long merge(unsigned long x, unsigned long y)
    {
        if(sizeof x == 4)
            return (x & 0xFFFF0000ul) | (y & 0x0000FFFFul);
        else
            return (x & 0xFFFFFFFF00000000ul) | (y & 0x00000000FFFFFFFFul);
    }
    

    You can also use conditional compilation

    unsigned long merge(unsigned long x, unsigned long y)
    {
    #if ULONG_MAX == 0xFFFFFFFFul
        return (x & 0xFFFF0000ul) | (y & 0x0000FFFFul);
    #else
        return (x & 0xFFFFFFFF00000000ul) | (y & 0x00000000FFFFFFFFul);
    #endif
    }