views:

564

answers:

5

I'm trying to swap bytes for an assignment, and I thought this would be the way to do it.

p points to the scalar object to be reversed size is the number of bytes of the object.

void *ReverseEndian(void *p, size_t size) 
{
    char *head = (char *)&p;
    char *tail = head + size - 1;

    for (; tail > head; --tail, ++head) {
        char temp = *head;
        *head = *tail;
        *tail = temp;
    }
    return p;
}

Is there something obviously wrong witht he above? I get an error with my professor's test code:

#define TestIt(a, b) TestReverse((void *)&(a),\
                     ReverseEndian((void *)&(b), sizeof(b)), sizeof(b))


int main()
char ch = 0x01, ch1 = ch;
   short sh = 0x0123, sh1 = sh;
   long lo = 0x01234567, lo1 = lo;
   float fl = 1234.567e27F, fl1 = fl;
   double db = 123456.567890, db1 = db;
   long double ld = 987654.321053e-204L, ld1 = ld;
   void *vp = (void *)0x0123, *vp1 = vp;
   char *cp = (char *)0x4567, *cp1 = cp;
   char *ip = (char *)0x89AB, *ip1 = ip;

   TestIt(ch1, ch);
   TestIt(sh1, sh);
   TestIt(lo1, lo);
   TestIt(fl1, fl);
   TestIt(db1, db);
   TestIt(ld1, ld);
   TestIt(vp1, vp);
   TestIt(cp1, cp);
   TestIt(ip1, ip);

   printf("ReverseEndian succeeded!\n");

   return EXIT_SUCCESS;
}

void TestReverse(const void *before, const void *after, size_t size)
{
   const char *cpBfore = (const char *)before;
   const char *cpAfter = (const char *)after;
   const char *tail;

   for (tail = cpBfore + (size - 1); size; --size)
      if (*tail-- != *cpAfter++)
      {
         fprintf(stderr, "ReverseEndian failed!\n");
         exit(EXIT_FAILURE);
      }
}
+1  A: 

char *head = (char *)&p should be char *head = (char *)p

+3  A: 

Here

char *head = (char *)&p;

you're defining a pointer that points to another pointer. So you have pointer -> pointer -> bytes which is obviously not what you want. Lucky the program didn't crash.

It must be char *head = (char *)p; so that each byte will be read from the memory pointed to by p.

AndiDog
Crystal
@Crystal: what is `p`, and where does it point? What do you want `head` to point to?
Alok
That way you'd swap the bytes of the address to `p`. When using the correct solution `(char *)p`, you can write to the bytes (pointed to by p) like `*head = somevalue;`, as you already do. Make sure you really understand the concept of pointers!
AndiDog
@Crystal - you do need to the address of the variable you are swapping the bytes of. But if you look in the macro TestIt, you are already taking the address of the variable there. Taking the address of the variable that holds the address is what AndiDog is pointing out.
R Samuel Klatchko
As a sidebar, you shouldn't need to cast to and from `void *` in C (so the `(char *)` cast here, and the `(void *)` casts in the OPs macro, are unnecessary).
caf
A: 

You shouldn't be taking the address of p

This should work:

void *ReverseEndian(void *p, size_t size) 
{
    char *head = (char *)p; // here
    char *tail = head + size - 1;

    for (; tail > head; --tail, ++head) {
        char temp = *head;
        *head = *tail;
        *tail = temp;
    }
    return p;
}
sergiom
+1  A: 

p is a pointer variable (i.e., a variable that holds a memory address of something), and in the following line:

char *head = (char *)&p;

...you're using &p, which gives you the address of the pointer variable itself, rather than the memory address value that the pointer variable contains (points to).

Did you mean to do this instead?

char *head = (char *)p;

By the way, your source code appears to reverse the order of an entire string, e.g. "Hello" --> "olleH" (unless I'm reading it wrong)

That's not the same thing as reversing endianness. The term endian usually refers to a multi-byte value that is stored with the most- or least-significant byte first.

As an example, the decimal value 43981 is expressed in hex as ABCD. In big-endian, the most-significant byte (AB) would be stored in the lower memory location, and the least-significant byte (CD) would be stored in the higher memory location.

In little-endian, the order is reversed; least-significant followed by most-significant: CDAB.

Scott Smith
Why isn't reversing a string the same as endianness? How is a 4-character string different than a 32-bit int, as far as swapping endianness is concerned?
tomlogic
@tomlogic - Endianness is the ordering of individually addressable sub-units (words, bytes, or even bits) within a longer data word. For example, given the following 16-bit values `0x1122, 0x3344, 0x5566, 0x7788`, the little-endian representation would look like `22 11 44 33 66 55 88 77`, whereas reversal of the bytes would look like `88 77 66 55 44 33 22 11`.
Scott Smith
@Scott Smith - got it. I assumed the function would only be used for a single value (p points to the scalar object to be reversed, size is the number of bytes of the object) in which case it's a generalized routine to handle a 16-bit, 32-bit or 64-bit integral type. +1 for good clarification.
tomlogic
A: 

You shouldn't be taking the address of p

This should work:

void *ReverseEndian(void *p, size_t size) 
{
    char *head = (char *)p; // here
    char *tail = head + size - 1;

    for (; tail > head; --tail, ++head) {
        char temp = *head;
        *head = *tail;
        *tail = temp;
    }
    return p;
}
sergiom