4

Is there a fast way to convert 4 chars into a 32bit int? I know i can loop through it like :

string key = "ABCD";
int val = 0;
for (int i = 0; i < 4; i++)
{
    int b = (int)key[i] * (int)Math.Pow(256, i);
    val += b;
}
// val = 1145258561

I would like something lower level, I know the chars are stored as bytes. I don't mind if its unsafe code because I am basically trying to write a 4 char string to an integer pointer location.

Proviance
  • 59
  • 1
  • 7

4 Answers4

8

You can first convert the string to a byte array using an appropriate encoding (see Encoding.GetEncoding) then you can use BitConverter.ToInt32 to convert the byte array to an integer.

string s = "ABCD";
byte[] bytes = encoding.GetBytes(s);  /* Use the correct encoding here. */
int result = BitConverter.ToInt32(bytes, 0);

Result:

1145258561

To get back the string from the integer you simply reverse the process:

int i = 1145258561;
byte[] bytes = BitConverter.GetBytes(i);
string s = encoding.GetString(bytes);

Result:

ABCD

Note that BitConverter class gives a result which is dependant on the endianness of the machine it is running on. If you want the code to be platform independent you could look at EndianBitConverter in Jon Skeet's MiscUtil library.


Performance

I tested the performance of three implementations:

Math.Pow

int convert1(string key)
{
    int val = 0;
    for (int i = 0; i < 4; i++)
    {
        int b = (int)key[i] * (int)Math.Pow(256, i);
        val += b;
    }
    return val;
}

BitConverter

int convert2(string key)
{
    byte[] bytes = encoding.GetBytes(key);
    int result = BitConverter.ToInt32(bytes, 0);
    return result;
}

Bit shifting

int convert3(string key)
{
    int val = 0;
    for (int i = 3; i >= 0; i--)
    {
        val <<= 8;
        val += (int)key[i];
    }
    return val;
}

Loop unrolled

int convert4(string key)
{
    return (key[3] << 24) + (key[2] << 16) + (key[1] << 8) + key[0];
}

Results

Biggest is best performance:

Method         Iterations per second
------------------------------------
Math.Pow                      690000
BitConverter                 2020000
Bit shifting                 4940000
Loop unrolled                8040000

Conclusion

If performance is critical then writing your own method to do bit shifting gets the best performance. Using the standard class BitConverter is probably fine for most situations where performance is not critical (assuming that you don't mind that it only works on little endian computers).

Community
  • 1
  • 1
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • that works really well, thanks! I will see if its fast enough for me. Is there a way to flip it back ? – Proviance Oct 04 '10 at 21:04
  • 1
    It's important to say that this will only work correctly for ASCII characters. `ASCIIEncoding` (or the `Encoding` classes in general) is implemented very dumb: It simply replaces characters by '?' if they can not be encoded. – AndiDog Oct 04 '10 at 21:07
  • thankyou! the bit shifting is what I was looking for. I haven't ever done any bit shifting in c# but I knew it had to be there somewhwere – Proviance Oct 04 '10 at 21:52
3

Use bytes, and the BitConverter:

byte[] bytes = ...;
int i = BitConverter.ToInt32(bytes, 0)
Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
2

Note that strings in C# contain Unicode characters, not bytes. I don't know what kind of problem you want to solve with this question, but be aware that you can only convert 4 bytes to a 32-bit integer. Converting a Unicode string only makes sense if you make assumptions about the byte encoding. So if you want to treat the text as Windows-1252 (very common Windows charset), you would first encode the string and the convert the bytes to an integer value.

byte[] bytes = Encoding.GetEncoding(1252).GetBytes("ABCÖ");
uint res = BitConverter.ToUInt32(bytes, 0);

The result is res == 0xD6434241 (on a little endian machine). 0xD6 is the Windows-1252 number for 'Ö'.

Depending on your problem, you may rather want to use bytes directly (Stefan Steinegger suggested that already).

AndiDog
  • 68,631
  • 21
  • 159
  • 205
  • thanks. I am creating an aTree link list in a memory block. The 4 chars are actually a Key for a dictionary so I am just hashing them. I don't need to worry about unicode (whew). – Proviance Oct 04 '10 at 21:30
0

More simple, its better :

/*
** Made by CHEVALLIER Bastien
** Prep'ETNA Promo 2019
*/

#include <stdio.h>

int main()
{
  int i;
  int x;
  char e = 'E';
  char t = 'T';
  char n = 'N';
  char a = 'A';

  ((char *)&x)[0] = e;
  ((char *)&x)[1] = t;
  ((char *)&x)[2] = n;
  ((char *)&x)[3] = a;

  for (i = 0; i < 4; i++)
    printf("%c\n", ((char *)&x)[i]);
  return 0;
}
cheval_b
  • 31
  • 1
  • 4