DarkAmgine
DarkAmgine

Reputation: 237

C# - Making one Int64 from two Int32s

Is there a function in c# that takes two 32 bit integers (int) and returns a single 64 bit one (long)?

Sounds like there should be a simple way to do this, but I couldn't find a solution.

Upvotes: 16

Views: 12118

Answers (7)

Jan
Jan

Reputation: 2249

There is a problem when i2 < 0 - high 32 bits will be set (0xFFFFFFFF,1xxx... binary) - thecoop was wrong
Better would be something like (Int64)(((UInt64)i1 << 32) | (UInt32)i2)

Or simply C++ way

public static unsafe UInt64 MakeLong(UInt32 low, UInt32 high)
{
    UInt64 retVal;
    UInt32* ptr = (UInt32*)&retVal;
    *ptr++ = low;
    *ptr = high;
    return retVal;
}

UInt64 retVal;
unsafe
{
    UInt32* ptr = (UInt32*)&retVal;
    *ptr++ = low;
    *ptr = high;
}

But the best solution found then here ;-)
[StructLayout(LayoutKind.Explicit)]
[FieldOffset()]
https://stackoverflow.com/questions/12898591
(even w/o unsafe) Anyway FieldOffset works for each item, so you have to specify position of each half separate and remember negative #s are zero complements, so ex. low <0 and high >0 will not make sense - for example -1,0 will give Int64 as 4294967295 probably.

Upvotes: 0

HelloWorld
HelloWorld

Reputation: 3749

Be careful with the sign bit. Here is a fast ulong solution, that is also not portable from little endian to big endian:

    var a = 123;
    var b = -123;

    unsafe
    {
        ulong result = *(uint*)&a;

        result <<= 32;
        result |= *(uint*)&b;
    }

Upvotes: 2

Jake Drew
Jake Drew

Reputation: 2340

Just for clarity... While the accepted answer does appear to work correctly. All of the one liners presented do not appear to produce accurate results.

Here is a one liner that does work:

long correct = (long)left << 32 | (long)(uint)right;

Here is some code so you can test it for yourself:

long original = 1979205471486323557L;
int left = (int)(original >> 32);
int right = (int)(original & 0xffffffffL);

long correct = (long)left << 32 | (long)(uint)right;

long incorrect1 = (long)(((long)left << 32) | (long)right);
long incorrect2 = ((Int64)left << 32 | right);
long incorrect3 = (long)(left * uint.MaxValue) + right;
long incorrect4 = (long)(left * 0x100000000) + right;

Console.WriteLine(original == correct);
Console.WriteLine(original == incorrect1);
Console.WriteLine(original == incorrect2);
Console.WriteLine(original == incorrect3);
Console.WriteLine(original == incorrect4);

Upvotes: 23

JaredPar
JaredPar

Reputation: 755209

Try the following

public long MakeLong(int left, int right) {
  //implicit conversion of left to a long
  long res = left;

  //shift the bits creating an empty space on the right
  // ex: 0x0000CFFF becomes 0xCFFF0000
  res = (res << 32);

  //combine the bits on the right with the previous value
  // ex: 0xCFFF0000 | 0x0000ABCD becomes 0xCFFFABCD
  res = res | (long)(uint)right; //uint first to prevent loss of signed bit

  //return the combined result
  return res;
}

Upvotes: 26

Paul Alexander
Paul Alexander

Reputation: 32377

Gotta be careful with bit twiddling like this though cause you'll have issues on little endian/big endian machines (exp Mono platforms aren't always little endian). Plus you have to deal with sign extending. Mathematically the following is the same but deals with sign extension and is platform agnostic.

return (long)( high * uint.MaxValue ) + low;

When jitted at runtime it will result in performance similar to the bit twiddling. That's one of the nice things about interpreted languages.

Upvotes: 0

viraptor
viraptor

Reputation: 34195

This should do the trick

((Int64) a << 32 | b)

Where a and b are Int32. Although you might want to check what happens with the highest bits. Or just put it inside an "unchecked {...}" block.

Upvotes: 0

thecoop
thecoop

Reputation: 46128

Try

(long)(((long)i1 << 32) | (long)i2)

this shifts the first int left by 32 bits (the length of an int), then ors in the second int, so you end up with the two ints concatentated together in a long.

Upvotes: 3

Related Questions