cbit-manipulationinterleave

Interleave 4 byte ints to 8 byte int


I'm currently working to create a function which accepts two 4 byte unsigned integers, and returns an 8 byte unsigned long. I've tried to base my work off of the methods depicted by this research but all my attempts have been unsuccessful. The specific inputs I am working with are: 0x12345678 and 0xdeadbeef, and the result I'm looking for is 0x12de34ad56be78ef. This is my work so far:

unsigned long interleave(uint32_t x, uint32_t y){
    uint64_t result = 0;
    int shift = 33;

    for(int i = 64; i > 0; i-=16){
        shift -= 8;
        //printf("%d\n", i);
        //printf("%d\n", shift);
        result |= (x & i) << shift;
        result |= (y & i) << (shift-1);
    }
}

However, this function keeps returning 0xfffffffe which is incorrect. I am printing and verifying these values using:

printf("0x%x\n", z);

and the input is initialized like so:

uint32_t x = 0x12345678;
uint32_t y = 0xdeadbeef;

Any help on this topic would be greatly appreciated, C has been a very difficult language for me, and bitwise operations even more so.


Solution

  • With bit-shifting and bitwise operations (endianness independent):

    uint64_t interleave(uint32_t x, uint32_t y){
    
        uint64_t result = 0;
    
        for(uint8_t i = 0; i < 4; i ++){
            result |= ((x & (0xFFull << (8*i))) << (8*(i+1)));
            result |= ((y & (0xFFull << (8*i))) << (8*i));
        }
    
        return result;
    }
    

    With pointers (endianness dependent):

    uint64_t interleave(uint32_t x, uint32_t y){
    
        uint64_t result = 0;
    
        uint8_t * x_ptr = (uint8_t *)&x;
        uint8_t * y_ptr = (uint8_t *)&y;
        uint8_t * r_ptr = (uint8_t *)&result;
    
        for(uint8_t i = 0; i < 4; i++){
            *(r_ptr++) = y_ptr[i];
            *(r_ptr++) = x_ptr[i];
        }
    
        return result;
    
    }
    

    Note: this solution assumes little-endian byte order