10

I'm working on a homework assignment for my C++ class. The question I am working on reads as follows:

Write a function that takes an unsigned short int (2 bytes) and swaps the bytes. For example, if the x = 258 ( 00000001 00000010 ) after the swap, x will be 513 ( 00000010 00000001 ).

Here is my code so far:

#include <iostream>

using namespace std;

unsigned short int ByteSwap(unsigned short int *x);

int main()
{
  unsigned short int x = 258;
  ByteSwap(&x);

  cout << endl << x << endl;

  system("pause");
  return 0;
}

and

unsigned short int ByteSwap(unsigned short int *x)
{
  long s;
  long byte1[8], byte2[8];

  for (int i = 0; i < 16; i++)
  {
    s = (*x >> i)%2;

    if(i < 8)
    {
      byte1[i] = s;
      cout << byte1[i];
    }
    if(i == 8)
      cout << " ";

    if(i >= 8)
    {
      byte2[i-8] = s;
      cout << byte2[i];
    }
  }

  //Here I need to swap the two bytes
  return *x;
}   

My code has two problems I am hoping you can help me solve.

  1. For some reason both of my bytes are 01000000
  2. I really am not sure how I would swap the bytes. My teachers notes on bit manipulation are very broken and hard to follow and do not make much sense me.

Thank you very much in advance. I truly appreciate you helping me.

athspk
  • 6,722
  • 7
  • 37
  • 51
Rob S.
  • 3,599
  • 6
  • 30
  • 39
  • Complaints about your code: 1) I'd refer pass the short in directly rather than as a pointer. As written, your function tries to edit the passed in variable, which is pretty ugly. 2) If you insist on modifying the variable as it is passed in, I wouldn't bother to return it (this makes it surprising that your function edits it) and would use pass by reference instead of passing a pointer. 3) I would rather use bit operators and just use an array of two bytes (`char` or `unsigned char`), rather than storing each bit in a separate long. – Brian Oct 12 '10 at 17:29
  • See also a somewhat related question: http://stackoverflow.com/questions/3991478/building-a-32bit-float-out-of-its-4-composite-bytes-c – Brian Oct 21 '10 at 21:01

12 Answers12

26

New in C++23:

The standard library now has a function that provides exactly this facility:

#include <iostream>
#include <bit>

int main() {
  unsigned short x = 258;
  x = std::byteswap(x);
  std::cout << x << endl;
}

Original Answer:

I think you're overcomplicating it, if we assume a short consists of 2 bytes (16 bits), all you need to do is

  • extract the high byte hibyte = (x & 0xff00) >> 8;
  • extract the low byte lobyte = (x & 0xff);
  • combine them in the reverse order x = lobyte << 8 | hibyte;
nickelpro
  • 2,537
  • 1
  • 19
  • 25
nos
  • 223,662
  • 58
  • 417
  • 506
  • I'm not familiar with that syntax. Can you provide me a reference to it please? – Rob S. Oct 12 '10 at 15:15
  • 3
    @Rob S. : `&` : Bitwise and operation. `>>` and `<<` : Bit shifting operations. `|`: Bitwise or operation. That's sufficient explanation to make googling it really easy. Or just read http://en.wikipedia.org/wiki/Bitwise_operation – Brian Oct 12 '10 at 15:27
12

It looks like you are trying to swap them a single bit at a time. That's a bit... crazy. What you need to do is isolate the 2 bytes and then just do some shifting. Let's break it down:

uint16_t x = 258;

uint16_t hi = (x & 0xff00); // isolate the upper byte with the AND operator

uint16_t lo = (x & 0xff); // isolate the lower byte with the AND operator

Now you just need to recombine them in the opposite order:

uint16_t y = (lo << 8); // shift the lower byte to the high position and assign it to y
y |= (hi >> 8);         // OR in the upper half, into the low position

Of course this can be done in less steps. For example:

uint16_t y = (lo << 8) | (hi >> 8);

Or to swap without using any temporary variables:

uint16_t y = ((x & 0xff) << 8) | ((x & 0xff00) >> 8);       
John
  • 3,716
  • 2
  • 19
  • 21
Evan Teran
  • 87,561
  • 32
  • 179
  • 238
  • +1 nice, seems like everyone can type answers much faster and better than I can :D – Kenny Cason Oct 12 '10 at 15:18
  • This works and I really appreciate your answer. Can you please provide any reference or reading material on how it works. Particularly on what the ' & ' and ' | ' characters do. Thank you very much again :) – Rob S. Oct 12 '10 at 15:21
  • Those are the AND and OR logical bitwise operators in C. http://en.wikipedia.org/wiki/Bitwise_operation – Evan Teran Oct 12 '10 at 15:23
  • Thank you very much once again :) – Rob S. Oct 12 '10 at 15:25
5

You're making hard work of that.

You only neeed exchange the bytes. So work out how to extract the two byte values, then how to re-assemble them the other way around

(homework so no full answer given)

EDIT: Not sure why I bothered :) Usefulness of an answer to a homework question is measured by how much the OP (and maybe other readers) learn, which isn't maximized by giving the answer to the homewortk question directly...

The Archetypal Paul
  • 41,321
  • 20
  • 104
  • 134
  • Can you provide me with any reference or reading material on this? I believe most of my problem is that I lack a lot of background knowledge on this subject. – Rob S. Oct 12 '10 at 15:19
  • @Rob S. : One way to do this is with a `union`. See my answer for an example. Another way to do this is by ugly pointer casting. E.g. `short s = 258; unsigned char tmp = (*(unsigned char *)(&s))`; There is probably a better way. – Brian Oct 12 '10 at 15:25
  • @RobS if you're really taking a C++ class there must be class materials for that. If the class isn't providing them, find a different class! You're asking some very basic questions and shouldn't need pointers to answers (e.g. meaning of << etc) – The Archetypal Paul Oct 12 '10 at 15:32
  • 1
    Paul, my teacher barely speaks comprehensible English and gives me the impression he doesnt understand the subject very well himself. I did not purchase his class textbook because he listed it as being only 'recommended' and not 'required' and it was nearly 200 USD. I have been doing most of my learning on the Internet and through deciphering his notes. Lastly, I was more interested in | and &. I know what << does ;) – Rob S. Oct 12 '10 at 23:05
  • Fair enough - it just looked a little like you were looking to be spoonfed answers. Sounds like you could do with buying one of the popular (and not $200!) books on C++... – The Archetypal Paul Oct 13 '10 at 04:25
4

Here is an unrolled example to demonstrate byte by byte:

unsigned int swap_bytes(unsigned int original_value)
{
  unsigned int new_value = 0; // Start with a known value.
  unsigned int byte;          // Temporary variable.

  // Copy the lowest order byte from the original to
  // the new value:
  byte = original_value & 0xFF;  // Keep only the lowest byte from original value.
  new_value = new_value * 0x100; // Shift one byte left to make room for a new byte.
  new_value |= byte;             // Put the byte, from original, into new value.

  // For the next byte, shift the original value by one byte
  // and repeat the process:
  original_value = original_value >> 8; // 8 bits per byte.
  byte = original_value & 0xFF;  // Keep only the lowest byte from original value.
  new_value = new_value * 0x100; // Shift one byte left to make room for a new byte.
  new_value |= byte;             // Put the byte, from original, into new value.

  //...
  return new_value;
}
Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
3

Ugly implementation of Jerry's suggestion to treat the short as an array of two bytes:

#include <iostream>
typedef union mini
{
    unsigned char b[2];
    short s;
} micro;
int main()
{
    micro x;
    x.s = 258;
    unsigned char tmp = x.b[0];
    x.b[0] = x.b[1];
    x.b[1] = tmp;
    std::cout << x.s << std::endl;
}
Brian
  • 25,523
  • 18
  • 82
  • 173
2
#include <stdio.h>

int main()
{
   unsigned short a = 258;
   a = (a>>8)|((a&0xff)<<8);
   printf("%d",a);
}
Jonas Stein
  • 6,826
  • 7
  • 40
  • 72
Sirish
  • 9,183
  • 22
  • 72
  • 107
2

Using library functions, the following code may be useful (in a non-homework context):

unsigned long swap_bytes_with_value_size(unsigned long value, unsigned int value_size) {
    switch (value_size) {
        case sizeof(char):
            return value;

        case sizeof(short):
            return _byteswap_ushort(static_cast<unsigned short>(value));

        case sizeof(int):
            return _byteswap_ulong(value);

        case sizeof(long long):
            return static_cast<unsigned long>(_byteswap_uint64(value));

        default:
            printf("Invalid value size");
            return 0;
    }
}

The byte swapping functions are defined in stdlib.h at least when using the MinGW toolchain.

BullyWiiPlaza
  • 17,329
  • 10
  • 113
  • 185
1

A bit old fashioned, but still a good bit of fun.

XOR swap: ( see How does XOR variable swapping work? )

    #include <iostream>
    #include <stdint.h>
    int main()
    {
        uint16_t x = 0x1234;
        uint8_t *a = reinterpret_cast<uint8_t*>(&x);
        std::cout << std::hex << x << std::endl;
        *(a+0) ^= *(a+1) ^= *(a+0) ^= *(a+1);
        std::cout << std::hex << x << std::endl;
    }
Community
  • 1
  • 1
don bright
  • 1,113
  • 1
  • 11
  • 15
1

While you can do this with bit manipulation, you can also do without, if you prefer. Either way, you shouldn't need any loops though. To do it without bit manipulation, you'd view the short as an array of two chars, and swap the two chars, in roughly the same way as you would swap two items while (for example) sorting an array.

To do it with bit manipulation, the swapped version is basically the lower byte shifted left 8 bits ord with the upper half shifted left 8 bits. You'll probably want to treat it as an unsigned type though, to ensure the upper half doesn't get filled with one bits when you do the right shift.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • So without bit manipulation are you talking about typecasting the short into a char and breaking it in half? I dont have much experience with this but I think it would be interesting to try. – Rob S. Oct 12 '10 at 15:17
  • @Rob S.: You'd typically take its address, and cast that to pointer to char, or you could use a union of the two types (`short` and `char [2]`). Absent a reason to do otherwise, I'd probably use the pointer. – Jerry Coffin Oct 12 '10 at 15:25
1

This should also work for you.

#include <iostream>

int main() {
    unsigned int i = 0xCCFF;
    std::cout << std::hex << i << std::endl;

    i  = ( ((i<<8) & 0xFFFF) | ((i >>8) & 0xFFFF)); // swaps the bytes

    std::cout << std::hex << i << std::endl;
}
Kenny Cason
  • 12,109
  • 11
  • 47
  • 72
0

This is a problem:

byte2[i-8] = s;
cout << byte2[i];//<--should be i-8 as well

This is causing a buffer overrun.

However, that's not a great way to do it. Look into the bit shift operators << and >>.

Skizz
  • 69,698
  • 10
  • 71
  • 108
0

A method without bit shifting, pure arithmetics:

unsigned short int x = 258;
unsigned short answer = x/256 + (x%256)*256;
Tomek Ab
  • 1
  • 2
  • Note that many optimizing compilers will inherently translate multiplications and divisions by powers of 2 into bit-shift operations. – Adrian Mole Mar 03 '23 at 15:34
  • Of course! Bit shift is more efficient no doubt about that! I just wanted to show another way to write a code solving the given problem. If you put away efficiency it looks nice to me :) – Tomek Ab Mar 06 '23 at 01:06