dikidera
dikidera

Reputation: 2053

Swapping endiannes in C

I have this string

c1eb044f0708015b267913fc4dff5aabe3dd4a97f10f7ba935cd360000000000

How does one swap it so it becomes

000000000036cd35a97b0ff1974adde3ab5aff4dfc1379265b0108074f04ebc1

Those two are basically examples, but that is what i need to do, but not know how as i have very little knowledge of C.

The above two strings are actually unsigned char[] in the C program

P.S Don't think i didn't go through google. I did, but i found very little of what i needed so every attempt to do that failed.

Upvotes: 1

Views: 584

Answers (5)

phoxis
phoxis

Reputation: 61990

If you have a string: "12ab\0" then the reverse endian of this string would be "\0ba21" .

If you have a numeric: 0x12ab then the reverse endian of this numeric would be 0xab12 .

Which one do you want.

Here is a function for converting between endian, which will handle the passed argument as a block of memory and change the endian.

Code

#include <stdio.h>
typedef struct _test {
  unsigned int a, b;
} test;

/* x: base address of the memory
 * n: length of the memory
 */
void reverse_endian (void *x, int n)
{
  char *arr_conv, *arr, t;

  arr = arr_conv = (char *) x;
  arr += (n-1);

  n/=2;

  while (n)
  {
    t = *arr_conv;
    *arr_conv = *arr;
    *arr = t;

    n--;
    arr_conv++;
    arr--;
  }
}


int main (void)
{
  char str1[] = "c1eb044f0708015b267913fc4dff5aabe3dd4a97f10f7ba935cd360000000000";
  char str2[] = "hellio";
  /* Assigns the str1 as hex values */
  unsigned char str3[] = {0xc1, 0xeb, 0x04, 0x4f, 0x07, 0x08, 0x01, 0x5b, 0x26, 0x79, 0x13, 0xfc, 0x4d, 0xff, 0x5a, 0xab, 0xe3, 0xdd, 0x4a, 0x97, 0xf1, 0x0f, 0x7b, 0xa9, 0x35, 0xcd, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00};
  test x;
  char q = 0x12;
  int v = 0x1234abcd;
  int i, n;

  x.a = 0x12ab34cd;
  x.b = 0x98ef76af;

  printf ("\nNormal : x.a = %x x.b = %x", x.a, x.b);
  reverse_endian (&x, sizeof (x));
  printf ("\nReverse: x.a = %x x.b = %x", x.a, x.b);

  printf ("\nNormal : q = %x", q);
  reverse_endian (&q, sizeof (q));
  printf ("\nReverse: q = %x", q);

  printf ("\nNormal : q = %x", v);
  reverse_endian (&v, sizeof (v));
  printf ("\nReverse: q = %x", v);

  printf ("\nNormal : str1 = %s", str1);
/* minus 1 to avoid the trailing nul character */
  reverse_endian (str1, sizeof (str1) - 1);
  printf ("\nReverse: str1 = %s", str1);

  printf ("\nNormal : str2 = %s", str2);
/* minus 1 to avoid the trailing nul character */
  reverse_endian (str2, sizeof (str2) - 1);
  printf ("\nReverse: str2 = %s", str2);

  printf ("\nNormal : str3 = ");
  n = sizeof (str3);
  for (i=0; i < n; i++)
  {
    printf ("%x", (str3[i]>>4)&0x0f);
    printf ("%x", str3[i]&0x0f);
  }
  reverse_endian (str3, sizeof (str3));
  printf ("\nReversed: str3 = ");
  for (i=0; i < n; i++)
  {
    printf ("%x", (str3[i]>>4)&0x0f);
    printf ("%x", str3[i]&0x0f);
  }

  printf ("\n");
  return 0;
}

Output

Normal : x.a = 12ab34cd x.b = 98ef76af
Reverse: x.a = af76ef98 x.b = cd34ab12
Normal : q = 12
Reverse: q = 12
Normal : q = 1234abcd
Reverse: q = cdab3412
Normal : str1 = c1eb044f0708015b267913fc4dff5aabe3dd4a97f10f7ba935cd360000000000
Reverse: str1 = 000000000063dc539ab7f01f79a4dd3ebaa5ffd4cf319762b5108070f440be1c
Normal : str2 = hellio
Reverse: str2 = oilleh
Normal : str3 = c1eb044f0708015b267913fc4dff5aabe3dd4a97f10f7ba935cd360000000000
Reversed: str3 = 000000000036cd35a97b0ff1974adde3ab5aff4dfc1379265b0108074f04ebc1

Note that the strings str1, str2 are simply reversed, because each character of the string is one byte. The same character string you have provided is represented as byte string in str3. Its hex values are shown as output. The operations for all the data are identical, as it is only concerned to memory byte ordering.

Upvotes: 0

Steve Jessop
Steve Jessop

Reputation: 279415

Slight alternative to Micah's answer. I assume that the size is precalculated and even, and check that it's greater than 0 because s-2 is potentially UB. I modify the string in-place just for variety.

static inline void swap_uchar(unsigned char *l, unsigned char *r) {
    unsigned char tmp = *l;
    *l = *r;
    *r = tmp;
}

void reverse_pairs(unsigned char *s, size_t size) {
    if (size > 0) {
        for (unsigned char *l=s, *r=s+size-2; l < r; l += 2, r -= 2) {
            swap_uchar(l, r);
            swap_uchar(l+1, r+1);
        }
    }
}

Upvotes: 0

DigitalRoss
DigitalRoss

Reputation: 146251

This seems to do what you want, include at least string.h and stdlib.h.

unsigned char *stringrev(const unsigned char *s) {
  size_t n = strlen((const char *)s);
  unsigned char *r = malloc(n + 1);

  if (r != NULL && !(n & 1)) {
    const unsigned char *fp = s;
    unsigned char *rp = r + n;

    for(*rp = '\0'; n > 1; n -= 2) {
        *--rp = fp[1];
        *--rp = fp[0];
        fp += 2;
    }
  }
  return r;
}

Upvotes: 0

Micah Hainline
Micah Hainline

Reputation: 14437

for (int i = 0; i < size; i += 2) {
    myNewStr[size - i - 2] = myStr[i];
    myNewStr[size - i - 1] = myStr[i + 1]; 
}

Upvotes: 6

John
John

Reputation: 16007

Something like this; probably not perfect but gives you the idea. You'll want appropriate error checking, initialization of your buffer, etc.

Edit: I made an assumption I shouldn't have, possibly. I interpreted your string as hex representations of bytes, so I took c1 as an unsigned char and switched it with 00, for example. If your string is actually lowercase c, the number 1, etc., then Micah's answer is what you want, not mine.

void reverse_string(unsigned char *buf, int length)
{
    int i;
    unsigned char temp;

    for (i = 0; i < length / 2; i++)
    {
        temp = buf[i];
        buf[i] = buf[length - i - 1];
        buf[length - i - 1] = temp;
    }   
}

Upvotes: 1

Related Questions