2
unsigned long swap_bytes(unsigned long n) {
    unsigned char bytes[8];
    unsigned long temp;
    bytes[0] = (n >> ??) & 0xff;
    bytes[1] = (n >> ??) & 0xff; 
    // ...
}

I am really confused on how to shift an 8 byte unsigned long from ex: 0x12345678deadbeef to 0x34127856addeefbe. I started this but I am now stuck. Please help.

Yunnosch
  • 21,438
  • 7
  • 35
  • 44
dp123
  • 21
  • 4
  • `unsigned long` is probably not wide enough to hold `0x12345678deadbeef `. Do you mean `unsigned long long` ? – Jean-François Fabre Sep 09 '17 at 20:13
  • Continue as you started. Shift and mask each byte into the array, and build the result in a complementary manner. `unsigned` was a good choice. – Weather Vane Sep 09 '17 at 20:13
  • `long` is *at least* the size of `int`. I suggest you `printf("%zu\n", sizeof(long))` to establish that. – Weather Vane Sep 09 '17 at 20:17
  • It is suppose to be unsigned long. But what do I shift it by, is the problem that I have. Also, I am not sure if 0xff is the correct mask. I don't like shifting and masking because it confuses me but that is the only way I am allowed to approach this function. – dp123 Sep 09 '17 at 20:42
  • 2
    If you need a specific width, use fixed width types, don't rely on standard types having a specific width. – too honest for this site Sep 09 '17 at 20:45

3 Answers3

5

You can mask every other byte, in both versions, using & binary AND.
Then shift both masked values, in opposite directions and combine them using | binary OR.

n =   ((n & 0xff00ff00ff00ff00ull)>>8ull)
    | ((n & 0x00ff00ff00ff00ffull)<<8ull);

In case it is 4byte (what I consider an unsigned long in contrast to the unsigned long long, but that is implementation specific), then the code is

n =   ((n & 0xff00ff00ul)>>8ul)
    | ((n & 0x00ff00fful)<<8ul);
Yunnosch
  • 21,438
  • 7
  • 35
  • 44
  • 1
    Great one-liner! – J...S Sep 09 '17 at 20:41
  • This makes sense to me. Thank you so much. But why does my value of n show as 4050765991979987505? Instead of 12345678deadbeef? The swapped answer is 3978988777685397810 instead of 34127856addeefbe. Why is that? – dp123 Sep 09 '17 at 20:48
  • Study the printf docu to find out how to print all kinds of sizes and if so desired in hex. In my test I used `printf("%I64x\n", n);`, with gcc windows. – Yunnosch Sep 09 '17 at 20:51
  • @dp123 Are you sure that `sizeof(unsigned long)` is `8` on your machine? If not it may overflow which may be the reason for incorrect output. – J...S Sep 09 '17 at 20:53
  • Is there a way i can convert the n to hex before return? – dp123 Sep 09 '17 at 20:54
  • Please make a separate question with the details of what you want to achieve. Hex and decimal are representations, you get them by parameterising printf accordingly, the stored value is identical. That is as long as you do not store them as a sequence of characters in a "string". – Yunnosch Sep 09 '17 at 20:56
  • @J....S Yes, I checked it in gcc using: cpp -dD /dev/null | grep __SIZEOF_LONG__ i got #define __SIZEOF_LONG__ 8 – dp123 Sep 09 '17 at 21:04
  • Still better off using `` with `uint64_t` for unsigned 64bit integers (and `UINT64_C` for defining unsigned 64bit integer constants). – ndim Sep 10 '17 at 19:57
  • @ndim True, that's what I did in my test to ensure 8 bytes. – Yunnosch Sep 10 '17 at 21:57
0

You could try this

void swap(char *ptr, int i, int j)
{
    char temp=*(ptr+i);
    *(ptr+i)=*(ptr+j);
    *(ptr+j)=temp;
}
int main()
{
    //unsigned long n = 0x12345678deadbeef;
    uint64_t n = 0x12345678deadbeef;

    char *ptr=(char *)&n;

    swap(ptr, 0, 1);
    swap(ptr, 2, 3);
    swap(ptr, 4, 5);
    swap(ptr, 6, 7);
}

The address of n is cast into a char pointer and stored in ptr.

ptr+i will give the address of the ith byte of n whose value (ie, *(ptr+i)) is modified appropriately by the swap() function.

Edit: If you are not sure if your unsigned long's size is 8 bytes, you could use uint64_t from inttypes.h.

J...S
  • 4,713
  • 1
  • 15
  • 34
0

universal & horrible

void swapbytes(void *p, size_t size)
{
    uint8_t tmp, *ptr = p;

    for (size_t i = 0; i < (size - 1); i += 2)
    {
        tmp = *(ptr + i);
        *(ptr + i) = *(ptr + i + 1);
        *(ptr + i + 1) = tmp;
    }
}

usage:

uint64_t n;


swapbytes(&n, sizeof n);
0___________
  • 34,740
  • 4
  • 19
  • 48
  • What's wrong with OPs approach using shifts? After all they are not implementation-specific and don't invoke undefined behaviour like your first approach. Horrible - indeed. – too honest for this site Sep 09 '17 at 20:46