3

I am doing a homework that requires me to write a function that takes a long value and returns with its bytes in reverse order in C, the prototype for the function is given, which is

long swapLong(long x)

and my code looks like this :

long swapLong(long in)
{
    long out;
    char *inp = (char *) &in ;
    char *outp = (char *) &out;

    int i=0;
    for (i=0; i<8 ;i++)
    {    
        outp[i] = inp[7-i]; 
    }

    return out;
} 

if the input of the function is 0x1122334455667788

it should return 0x8877665544332211

however, when i test it with

long test2 = 0x1122334455667788;
long result2= swapLong(test2);
printf("0x %lx\n", test2);
printf("0x %lx\n", result2);

the result is 0x44332211

it seems like the function only swaps the first half oh the input and I don't know what happens to the second half

I have write another function called " int swapInt( int x) ", using similar idea with swapLong() and it works great.... so I dont know what did I do wrong for swapLong()

Carl Norum
  • 219,201
  • 40
  • 422
  • 469
Ted Woo
  • 33
  • 2
  • 4
    Is `long` a 32-bit type on your machine? – Carl Norum Jan 21 '13 at 07:23
  • 2
    You should use the `uint64_t` type from `stdint.h`. Its guaranteed to be 64 bits. Besides that, use bitwise operators for the byte-swapping. – jweyrich Jan 21 '13 at 07:25
  • 1
    As a more editorial aside, you can also solve this problem using bitwise operators, which will help you avoid violating strict aliasing rules. Check out an implementation of `htonl` for an example. – Carl Norum Jan 21 '13 at 07:26
  • Carl Norum:I think long should be 64-bit type on my computer, I am not sure. jweyrich: what do you mean by uint64_t type? how do I use that? – Ted Woo Jan 21 '13 at 07:29
  • 2
    @TedWoo Add `#include ` at the top of your program. And `sizeof (long)` will tell you how many bytes; `i – Potatoswatter Jan 21 '13 at 07:31
  • Did you get correct output when your code prints value of `test2`? If it prints correctly, then the `long` is 64 bits in your system. – SKi Jan 21 '13 at 07:37
  • 1
    read `man endian`: you may use macros from it for byte-order conversion. – Eddy_Em Jan 21 '13 at 07:44

4 Answers4

3

You might like to use sizeof(long)instead of 8.

...
size_t i;
size_t sizeLong = sizeof(long);
for (i=0; i<sizeLong ;i++)
{    
    outp[i] = inp[sizeLong-i-1]; 
}
...
WhozCraig
  • 65,258
  • 11
  • 75
  • 141
alk
  • 69,737
  • 10
  • 105
  • 255
  • Rollback that change if the (-1) isn't right, but I'm pretty sure it was what was missing. The first hit through the loop was pulling the low byte from `imp[sizeof(long)], which is one too many. Should work now (famous last words). – WhozCraig Jan 21 '13 at 07:45
  • I tried it out again but then the result is still 0x44332211, I still cannot see the second part. – Ted Woo Jan 21 '13 at 07:51
  • @TedWoo do yourself a favor and put this at the top of your code: `printf("sizeof(long) = %lu\n", sizeof(long));` From what you're showing your long values are only 32 bits long (which is not uncommon at all on a 32bit platform). You said the in your question the "result is 0x44332211". That would be for the *second* `printf`. What was the result of the *first* `printf`? The one that is supposed be printing the *original* value of `test2`?? – WhozCraig Jan 21 '13 at 07:55
  • @WhozCraig I did what you say and the result is "sizeof(long) = 8", so doesnt that meant my long is 64 bits? since 1 byte is 8 bits – Ted Woo Jan 21 '13 at 08:04
  • @TedWoo That is exactly what it means, and I'm therefore stymied. Alk's code should easily rotate your bytes correctly. It does mine (but I know I have 64bit longs too: I input `0x1122334455667788` and my result is `0x8877665544332211`, exactly as expected.) How your `long` is 64bits in one function, and 32bits in another is completely odd. And the original value (test2) is printing full-64bits in the prior `printf` ?? – WhozCraig Jan 21 '13 at 08:11
  • yeah my original value is printing full-64 bits, which is 0x1122334455667788 , and I have no idea why my result is only 4 bytes -.-.. your code should work. I guess its the program I am using , I am actually using a program that my school provides, which I am not sure what it is. I guess this code will work fine if I use the actual C compiler like visual studio . Thanks for help anyways :D – Ted Woo Jan 21 '13 at 08:24
  • @TedWoo try it on [ideone.com](https://ideone.com/yEhPZa) or some other code sites just for some peace of mind. The one linked uses known-64bit values by including `stdint.h` and using `int64_t`. – WhozCraig Jan 21 '13 at 08:26
2

Your code works fine on my system with your given input. I am pretty sure your long is 32 bits.

I am not allowed to edit my comment after 5 minutes so i will write it here.

C ensures that int must be at least as big as short and long must be atleast big as int. So your compiler chooses the best size based on the target platform (processor).

Deepankar Bajpeyi
  • 5,661
  • 11
  • 44
  • 64
  • Really? so this code is working depends on different kinds of system? how do I change my long into 64 bits then ? Thanks for the quick respond – Ted Woo Jan 21 '13 at 07:44
  • @TedWoo Well I doubt you can change your long . But you can use uint64_t which is a 64-bit type. Just include stdint.h in your program. If you want to play around with your friends you can do #define long uint64_t. after including stdint.h :P. But thats totally not recommended lol – Deepankar Bajpeyi Jan 21 '13 at 07:49
1

From what you describe you seem to be ignoring a warning you get for truncated constant value

long test2 = 0x1122334455667788; // 1234605616436508552 > 2^32-1

since your longs appear to be only 32-bit.

Use sizeof() in your loop instead of 8 and it should work fine.

at the start of your program you could write

assert( sizeof(long) == 4 ); // to see if it is 32-bit or not.
AndersK
  • 35,813
  • 6
  • 60
  • 86
0

Work out what's going on here for further enlightenment:

long swapLong(long x)
{
    int s = sizeof(long);
    long r = 0;
    for(int i=0; i<s; ++i)
    {
        r <<= 8;
        r |= x & 0xff;
        x >>= 8;
    }
    return r;
}
Charlie Skilbeck
  • 1,081
  • 2
  • 15
  • 38