2

Possible Duplicate:
convert big endian to little endian in C [without using provided func]

I'm having trouble with this one part: If I wanted to take a 32 bit number, and I want to shift its bytes (1 byte = 8 bits) from big endian to little endian form. For example:

Lets say I have the number 1.

In 32 bits this is what it would look like:

1st byte 2nd byte 3rd byte 4th byte
00000000 00000000 00000000 00000001

I want it so that it looks like this:

4th byte 3rd byte 2nd byte 1st byte 
00000001 00000000 00000000 00000000 

so that the byte with the least significant value appears first. I was thinking you can use a for loop, but I'm not exactly sure on how to shift bits/bytes in C++. For example if a user entered in 1 and I had to shift it's bits like the above example, I'm not sure how I would convert 1 into bits, then shift. Could anyone point me in the right direction? Thanks!

Community
  • 1
  • 1
user200081
  • 563
  • 2
  • 12
  • 24
  • 2
    @NPE how can it be a duplicate if it's not even the same language? – Luchian Grigore Nov 30 '12 at 20:38
  • 1
    Because most if not all of the rules about numbers and operations on them carry over from C to C++? – cHao Nov 30 '12 at 20:41
  • @LuchianGrigore: Sure, but in my view it's still a duplicate since it's explicitly about "shifting bits and bytes" and not about "how do I do this in a fancy C++ style". Of course the community can decide otherwise. – NPE Nov 30 '12 at 20:43
  • @NPE imo the most elegant solution here doesn't have any bitshifting in it. – Luchian Grigore Nov 30 '12 at 21:07
  • @cHao the idea is that there are more rules & options in C++. Would you close a question about dynamic sized arrays tagged C++ as a dupe of a C question that suggests subsequent `malloc`s? **No**. You'd suggest a `std::vector`, even though the same rules about numbers and operations apply. – Luchian Grigore Nov 30 '12 at 21:08
  • @LuchianGrigore: "The most elegant solution here", pretty as it is, relies on IB. As will most solutions that aren't shifting the bits of an unsigned number, which you could do exactly the same in C. :) – cHao Dec 01 '12 at 01:15
  • @cHao I don't see how it relies on IB. – Luchian Grigore Dec 01 '12 at 02:16
  • @LuchianGrigore: It makes assumptions about the size of a byte, which simply don't hold everywhere. – cHao Dec 01 '12 at 04:05

3 Answers3

4

<< and >> is the bitwise shift operators in C and most other C style languages.

One way to do what you want is:

int value = 1;
uint x = (uint)value;
int valueShifted = 
    ( x << 24) |                // Move 4th byte to 1st
    ((x << 8) & 0x00ff0000) |  // Move 2nd byte to 3rd
    ((x >> 8) & 0x0000ff00) |  // Move 3rd byte to 2nd
    ( x >> 24);                 // Move 4th byte to 1st
driis
  • 161,458
  • 45
  • 265
  • 341
  • I initially deleted my answer because I thought this was correct, but this exibits UB for large values of `value`. – Luchian Grigore Nov 30 '12 at 20:32
  • I think this fails for negatives. – Mooing Duck Nov 30 '12 at 20:32
  • *Can* fail for negatives, yes. Left-shifting a negative number technically invokes UB, and right-shifting it would shift in 1s on most systems. If the int were unsigned, maybe... – cHao Nov 30 '12 at 20:34
  • You are right, I fixed to use an unsigned intermediate variable, so logical shift should be used. – driis Nov 30 '12 at 20:36
  • @LuchianGrigore Although a union with `char[]` is UB, a simple cast to `char *` of the address of the variable is not, so you could swap it that way. – Neil Nov 30 '12 at 21:02
2
uint32_t n = 0x00000001;
std::reverse( (char*)&n, (char*)(&n + 1) );
assert( n == 0x01000000 );
BigBoss
  • 6,904
  • 2
  • 23
  • 38
  • Gets weird when chars are not 8 bits in size. If ints and chars are both 32 bits, for example, reversing does nothing. – cHao Nov 30 '12 at 21:34
  • @cHao `the C++ Standard guarantees that 1 == sizeof(char)` and in the question we have a 32 bit `unsigned int` type, so how you can simulate it using for example 7 bit char? – BigBoss Nov 30 '12 at 22:34
  • `sizeof(char) == 1` only promises that a char is one byte; it promises nothing about the size of that byte. The standard requires *at least* 8 bits per byte, but allows more. There have been (and still are, in special cases) systems with 8, 9, 16, 32, 36, even 64 bit bytes. In my 32-bit example, `sizeof(int) == 1`. With one byte, there's nothing to swap. – cHao Nov 30 '12 at 23:04
  • @cHao I use `uint32_t` from `stdint.h` where that header exist, we should have `uint8_t` and `int8_t` and because of that system should support 8 bit values. and the guarantee that `char` is smallest integer type, `char` should be 8 bit! – BigBoss Nov 30 '12 at 23:25
  • There's a reason there's a `CHAR_BIT` macro in ``. And that is, a `char` is not always exactly 8 bits wide. As for `uint8_t`, it's just a typedef, and a semi-optional one at that; if a system doesn't *have* such an exactly-8-bit type, it isn't required to provide the typedef. So if you want to guarantee 8 bit chars, to the point where compilation fails if they're any other size, then use `uint8_t`. But don't make any assumptions about the width of a `char` other than that it's one byte (not 8 bits!) in size. – cHao Dec 01 '12 at 00:21
  • @cHao If a byte is not 8 bits, how would the `<<24` still work and preserve endianess? – Luchian Grigore Dec 01 '12 at 02:17
  • @LuchianGrigore: A system that's responsible for communicating with the outside world would group the bits up into octets for transmission or storage for devices that don't deal in the native byte size. All you'd have to do is make sure the octets are in the right order, and in this case that just involves swapping octets. Not chars, not bytes, but *octets*. Bit shifting would work just fine for that, as again, you're not rearranging bytes -- you're rearranging groups of 8 bits. – cHao Dec 01 '12 at 04:03
0

Shifting is done with the << and >> operators. Together with the bit-wise AND (&) and OR (|) operators you can do what you want:

 int value = 1;
 int shifted = value << 24 | (value & 0x0000ff00) << 8 | (value & 0x00ff0000) >> 8 | (value & 0xff000000) >> 24;
JBaczuk
  • 13,886
  • 10
  • 58
  • 86
Bart Friederichs
  • 33,050
  • 15
  • 95
  • 195
  • I think this is UB for large values of `value`. – Luchian Grigore Nov 30 '12 at 20:33
  • §5.8/2 The value of `E1 << E2` is `E1` left-shifted `E2` bit positions; vacated bits are zero-filled. ...if E1 has a signed type and non-negative value, and `E1×2E2` is representable in the result type...; otherwise, the behavior is undefined. – Mooing Duck Nov 30 '12 at 20:36